mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-09-24 21:40:48 +02:00
150 lines
5.4 KiB
TypeScript
150 lines
5.4 KiB
TypeScript
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
import { expect } from '@wdio/globals'
|
|
import { tauri, tauriError, describePlugin } from '../helpers/index.js'
|
|
|
|
// The example spawns an echo server on this port: it replies with the request
|
|
// body and the request headers, and sets a `session-token` cookie on requests
|
|
// that do not carry one. It is also the only `http://` origin in the example's
|
|
// http scope.
|
|
const echoServer = 'http://localhost:3003'
|
|
|
|
describePlugin('http', () => {
|
|
it('fetch performs a GET and exposes status, url and headers', async () => {
|
|
const response = await tauri(async (api, url) => {
|
|
const response = await api.http.fetch(url, {
|
|
headers: { 'x-e2e-header': 'present' }
|
|
})
|
|
return {
|
|
ok: response.ok,
|
|
status: response.status,
|
|
url: response.url,
|
|
// the echo server mirrors the request headers back
|
|
echoedHeader: response.headers.get('x-e2e-header'),
|
|
body: await response.text()
|
|
}
|
|
}, echoServer)
|
|
expect(response.ok).toBe(true)
|
|
expect(response.status).toBe(200)
|
|
expect(response.url).toBe(`${echoServer}/`)
|
|
expect(response.echoedHeader).toBe('present')
|
|
expect(response.body).toBe('')
|
|
})
|
|
|
|
it('fetch sends a JSON body and parses the echoed response', async () => {
|
|
const payload = { message: 'hello from e2e', nested: { list: [1, 2, 3] } }
|
|
const response = await tauri(
|
|
async (api, url, payload) => {
|
|
const response = await api.http.fetch(`${url}/json`, {
|
|
method: 'POST',
|
|
headers: { 'content-type': 'application/json' },
|
|
body: JSON.stringify(payload)
|
|
})
|
|
return {
|
|
status: response.status,
|
|
contentType: response.headers.get('content-type'),
|
|
body: (await response.json()) as unknown
|
|
}
|
|
},
|
|
echoServer,
|
|
payload
|
|
)
|
|
expect(response.status).toBe(200)
|
|
expect(response.contentType).toBe('application/json')
|
|
expect(response.body).toEqual(payload)
|
|
})
|
|
|
|
it('fetch sends binary bodies and reads them back as bytes', async () => {
|
|
const bytes = [0, 1, 2, 127, 128, 254, 255]
|
|
const echoed = await tauri(
|
|
async (api, url, bytes) => {
|
|
const response = await api.http.fetch(`${url}/bytes`, {
|
|
method: 'PUT',
|
|
body: new Uint8Array(bytes)
|
|
})
|
|
return Array.from(new Uint8Array(await response.arrayBuffer()))
|
|
},
|
|
echoServer,
|
|
bytes
|
|
)
|
|
expect(echoed).toEqual(bytes)
|
|
})
|
|
|
|
it('fetch sends multipart form data', async () => {
|
|
const body = await tauri(async (api, url) => {
|
|
const form = new FormData()
|
|
form.append('foo', 'baz')
|
|
form.append('bar', 'qux')
|
|
const response = await api.http.fetch(`${url}/form`, {
|
|
method: 'POST',
|
|
body: form
|
|
})
|
|
return {
|
|
contentType: response.headers.get('content-type'),
|
|
text: await response.text()
|
|
}
|
|
}, echoServer)
|
|
expect(body.contentType).toMatch(/^multipart\/form-data; boundary=/)
|
|
expect(body.text).toContain('name="foo"')
|
|
expect(body.text).toContain('baz')
|
|
expect(body.text).toContain('name="bar"')
|
|
expect(body.text).toContain('qux')
|
|
})
|
|
|
|
it('the cookie jar stores and replays cookies across requests', async () => {
|
|
const result = await tauri(async (api, url) => {
|
|
// The jar is persisted in the app data dir, so an earlier run (or the
|
|
// requests above) may already hold the cookie: the first request then
|
|
// replays it instead of being handed a new one.
|
|
const first = await api.http.fetch(`${url}/cookies`)
|
|
await first.text()
|
|
// Either way the jar attaches it to the next request, which the echo
|
|
// server mirrors back as a `cookie` header without setting a new one.
|
|
const second = await api.http.fetch(`${url}/cookies`)
|
|
await second.text()
|
|
return {
|
|
setCookie: first.headers.get('set-cookie'),
|
|
replayedFirst: first.headers.get('cookie'),
|
|
replayed: second.headers.get('cookie'),
|
|
setAgain: second.headers.get('set-cookie')
|
|
}
|
|
}, echoServer)
|
|
if (result.replayedFirst === null) {
|
|
expect(result.setCookie).toMatch(/^session-token=test-value/)
|
|
} else {
|
|
expect(result.replayedFirst).toContain('session-token=test-value')
|
|
}
|
|
expect(result.replayed).toContain('session-token=test-value')
|
|
expect(result.setAgain).toBeNull()
|
|
})
|
|
|
|
it('fetch can be aborted', async () => {
|
|
const message = await tauriError(async (api, url) => {
|
|
const controller = new AbortController()
|
|
controller.abort()
|
|
await api.http.fetch(`${url}/aborted`, { signal: controller.signal })
|
|
}, echoServer)
|
|
expect(message).toMatch(/abort|cancel/i)
|
|
})
|
|
|
|
it('rejects URLs outside the configured scope', async () => {
|
|
const message = await tauriError((api) =>
|
|
api.http.fetch('http://localhost:3999/not-in-scope')
|
|
)
|
|
expect(message).toMatch(/url not allowed on the configured scope/)
|
|
})
|
|
|
|
it('network failures reject', async () => {
|
|
// Every in-scope origin is reachable, so route the request through a proxy
|
|
// nothing listens on to force a connection error.
|
|
const message = await tauriError(
|
|
(api, url) =>
|
|
api.http.fetch(url, { proxy: { all: 'http://127.0.0.1:1' } }),
|
|
echoServer
|
|
)
|
|
expect(message).toMatch(/error sending request/)
|
|
})
|
|
})
|