Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
5 changes: 0 additions & 5 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,3 @@ updates:
directory: /build
schedule:
interval: daily

- package-ecosystem: pip
directory: /test/wpt/tests/resources/test
schedule:
interval: daily
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: ["javascript", "python", "typescript"]
language: ["javascript", "typescript"]
# CodeQL supports [ $supported-codeql-languages ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support

Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ jobs:
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
with:
persist-credentials: false
submodules: recursive

# Setup node, install deps, and build undici prior to building icu-less node and testing
- name: Setup Node.js@${{ inputs.version }}
Expand Down Expand Up @@ -140,6 +141,19 @@ jobs:
echo git: $(git --version)
echo icu config: $(node -e "console.log(process.config)" | grep icu)

- name: Configure hosts file for WPT (Windows)
if: runner.os == 'Windows'
run: |
cd ${{ github.workspace }}\test\web-platform-tests\wpt
python wpt make-hosts-file | Out-File $env:SystemRoot\System32\drivers\etc\hosts -Encoding ascii -Append
shell: powershell

- name: Configure hosts file for WPT (Unix)
if: runner.os != 'Windows'
run: |
cd ${{ github.workspace }}/test/web-platform-tests/wpt
python3 wpt make-hosts-file | sudo tee -a /etc/hosts

- name: Run tests
run: npm run test:javascript:without-intl

Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
with:
persist-credentials: false
submodules: recursive

- name: Setup Node.js@${{ inputs.node-version }}
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
Expand All @@ -43,6 +44,19 @@ jobs:
run: npm ls --all
continue-on-error: true

- name: Configure hosts file for WPT (Windows)
if: runner.os == 'Windows'
run: |
cd ${{ github.workspace }}\test\web-platform-tests\wpt
python wpt make-hosts-file | Out-File $env:SystemRoot\System32\drivers\etc\hosts -Encoding ascii -Append
shell: powershell

- name: Configure hosts file for WPT (Unix)
if: runner.os != 'Windows'
run: |
cd ${{ github.workspace }}/test/web-platform-tests/wpt
python3 wpt make-hosts-file | sudo tee -a /etc/hosts

- name: Run tests with coverage
id: coverage
if: inputs.runs-on == 'ubuntu-latest' && inputs.node-version == 22
Expand Down
21 changes: 1 addition & 20 deletions .github/workflows/update-wpt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,9 @@ jobs:
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"

- name: Checkout Repository
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- name: Update WPT
run: |
rm -rf test/fixtures/wpt && mkdir test/fixtures/wpt &&

git clone https://github.com/web-platform-tests/wpt.git --depth=1 test/fixtures/tmp-wpt &&

mv test/fixtures/tmp-wpt/LICENSE.md test/fixtures/wpt/LICENSE.md &&

mv test/fixtures/tmp-wpt/common test/fixtures/wpt/common &&
mv test/fixtures/tmp-wpt/eventsource test/fixtures/wpt/eventsource &&
mv test/fixtures/tmp-wpt/fetch test/fixtures/wpt/fetch &&
mv test/fixtures/tmp-wpt/interfaces test/fixtures/wpt/interfaces &&
mv test/fixtures/tmp-wpt/mimesniff test/fixtures/wpt/mimesniff &&
mv test/fixtures/tmp-wpt/resources test/fixtures/wpt/resources &&
mv test/fixtures/tmp-wpt/service-workers test/fixtures/wpt/service-workers &&
mv test/fixtures/tmp-wpt/storage test/fixtures/wpt/storage &&
mv test/fixtures/tmp-wpt/websockets test/fixtures/wpt/websockets &&
mv test/fixtures/tmp-wpt/xhr test/fixtures/wpt/xhr &&

rm -rf test/fixtures/tmp-wpt
git submodule update --init --recursive
- name: Create Pull Request
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "test/web-platform-tests/wpt"]
path = test/web-platform-tests/wpt
url = https://github.com/web-platform-tests/wpt.git
48 changes: 32 additions & 16 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,34 +94,50 @@ Create a commit which includes all of the updated files in lib/llhttp.

`undici` runs a subset of the [`web-platform-tests`](https://github.com/web-platform-tests/wpt).

### Requirements:
- [Node core utils](https://github.com/nodejs/node-core-utils) setup with credentials.

To update every test, run the following commands. Typically you would only need to update the tests in a specific directory.
### Steps:

```bash
git node wpt resources
git node wpt interfaces
git node wpt common
git node wpt fetch
git node wpt xhr
git node wpt websockets
git node wpt mimesniff
git node wpt storage
git node wpt service-workers
git node wpt eventsource
git submodule update --init --recursive
```

#### Run the tests
### Run the tests

Run the tests to ensure that any new failures are marked as such.

You can mark tests as failing in their corresponding [status](./test/wpt/status) file.
Before running the tests for the first time, you must setup the testing environment.
```bash
cd test/web-platform-tests
node wpt-runner.mjs setup
```

To run all tests:

```bash
npm run test:wpt
```

To run a subset of tests:
```bash
cd test/web-platform-tests
node wpt-runner.mjs run [filter] [filterb]
```

To run a single file:
```bash
cd test/web-platform-tests
node wpt-runner.mjs run /path/to/test
```

### Debugging

Verbose logging can be enabled by setting the [`NODE_DEBUG`](https://nodejs.org/api/cli.html#node_debugmodule) flag:

```bash
npx cross-env NODE_DEBUG=UNDICI_WPT node --run test:wpt
```

(`npx cross-env` can be omitted on Linux and Mac)

<a id="lint"></a>
### Lint

Expand Down
4 changes: 2 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ module.exports = [
...neo({
ignores: [
'lib/llhttp',
'test/fixtures/wpt',
'test/fixtures/cache-tests',
'undici-fetch.js'
'undici-fetch.js',
'test/web-platform-tests/wpt'
],
noJsx: true,
ts: true
Expand Down
2 changes: 0 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,6 @@ module.exports.getGlobalOrigin = getGlobalOrigin
const { CacheStorage } = require('./lib/web/cache/cachestorage')
const { kConstruct } = require('./lib/core/symbols')

// Cache & CacheStorage are tightly coupled with fetch. Even if it may run
// in an older version of Node, it doesn't have any use without fetch.
module.exports.caches = new CacheStorage(kConstruct)

const { deleteCookie, getCookies, getSetCookies, setCookie, parseCookie } = require('./lib/web/cookies')
Expand Down
4 changes: 2 additions & 2 deletions lib/web/eventsource/eventsource-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ class EventSourceStream extends Transform {
this.buffer = this.buffer.subarray(this.pos + 1)
this.pos = 0
if (
this.event.data !== undefined || this.event.event || this.event.id || this.event.retry) {
this.event.data !== undefined || this.event.event || this.event.id !== undefined || this.event.retry) {
this.processEvent(this.event)
}
this.clearEvent()
Expand Down Expand Up @@ -367,7 +367,7 @@ class EventSourceStream extends Transform {
this.state.reconnectionTime = parseInt(event.retry, 10)
}

if (event.id && isValidLastEventId(event.id)) {
if (event.id !== undefined && isValidLastEventId(event.id)) {
this.state.lastEventId = event.id
}

Expand Down
18 changes: 12 additions & 6 deletions lib/web/eventsource/eventsource.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,11 @@ class EventSource extends EventTarget {
this.removeEventListener('open', this.#events.open)
}

if (typeof fn === 'function') {
const listener = webidl.converters.EventHandlerNonNull(fn)

if (listener !== null) {
this.addEventListener('open', listener)
this.#events.open = fn
this.addEventListener('open', fn)
} else {
this.#events.open = null
}
Expand All @@ -399,9 +401,11 @@ class EventSource extends EventTarget {
this.removeEventListener('message', this.#events.message)
}

if (typeof fn === 'function') {
const listener = webidl.converters.EventHandlerNonNull(fn)

if (listener !== null) {
this.addEventListener('message', listener)
this.#events.message = fn
this.addEventListener('message', fn)
} else {
this.#events.message = null
}
Expand All @@ -416,9 +420,11 @@ class EventSource extends EventTarget {
this.removeEventListener('error', this.#events.error)
}

if (typeof fn === 'function') {
const listener = webidl.converters.EventHandlerNonNull(fn)

if (listener !== null) {
this.addEventListener('error', listener)
this.#events.error = fn
this.addEventListener('error', fn)
} else {
this.#events.error = null
}
Expand Down
14 changes: 4 additions & 10 deletions lib/web/fetch/body.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,10 @@ function extractBody (object, keepalive = false) {

// Set type to `application/x-www-form-urlencoded;charset=UTF-8`.
type = 'application/x-www-form-urlencoded;charset=UTF-8'
} else if (isArrayBuffer(object)) {
// BufferSource/ArrayBuffer

// Set source to a copy of the bytes held by object.
source = new Uint8Array(object.slice())
} else if (ArrayBuffer.isView(object)) {
// BufferSource/ArrayBufferView

// Set source to a copy of the bytes held by object.
source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
} else if (webidl.is.BufferSource(object)) {
source = isArrayBuffer(object)
? new Uint8Array(object.slice())
: new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
} else if (webidl.is.FormData(object)) {
const boundary = `----formdata-undici-0${`${random(1e11)}`.padStart(11, '0')}`
const prefix = `--${boundary}\r\nContent-Disposition: form-data`
Expand Down
4 changes: 1 addition & 3 deletions lib/web/fetch/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ const { URLSerializer } = require('./data-url')
const { kConstruct } = require('../../core/symbols')
const assert = require('node:assert')

const { isArrayBuffer } = nodeUtil.types

const textEncoder = new TextEncoder('utf-8')

// https://fetch.spec.whatwg.org/#response-class
Expand Down Expand Up @@ -580,7 +578,7 @@ webidl.converters.XMLHttpRequestBodyInit = function (V, prefix, name) {
return V
}

if (ArrayBuffer.isView(V) || isArrayBuffer(V)) {
if (webidl.is.BufferSource(V)) {
return V
}

Expand Down
27 changes: 27 additions & 0 deletions lib/web/webidl/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,13 @@ webidl.is.URL = webidl.util.MakeTypeAssertion(URL)
webidl.is.AbortSignal = webidl.util.MakeTypeAssertion(AbortSignal)
webidl.is.MessagePort = webidl.util.MakeTypeAssertion(MessagePort)

webidl.is.BufferSource = function (V) {
return types.isArrayBuffer(V) || (
ArrayBuffer.isView(V) &&
types.isArrayBuffer(V.buffer)
)
}

// https://webidl.spec.whatwg.org/#es-DOMString
webidl.converters.DOMString = function (V, prefix, argument, opts) {
// 1. If V is null and the conversion is to an IDL type
Expand Down Expand Up @@ -783,6 +790,26 @@ webidl.converters.AbortSignal = webidl.interfaceConverter(
'AbortSignal'
)

/**
* [LegacyTreatNonObjectAsNull]
* callback EventHandlerNonNull = any (Event event);
* typedef EventHandlerNonNull? EventHandler;
* @param {*} V
*/
webidl.converters.EventHandlerNonNull = function (V) {
if (webidl.util.Type(V) !== OBJECT) {
return null
}

// [I]f the value is not an object, it will be converted to null, and if the value is not callable,
// it will be converted to a callback function value that does nothing when called.
if (typeof V === 'function') {
return V
}

return () => {}
}

module.exports = {
webidl
}
23 changes: 22 additions & 1 deletion lib/web/websocket/stream/websocketerror.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,28 @@ const { validateCloseCodeAndReason } = require('../util')
const { kConstruct } = require('../../../core/symbols')
const { kEnumerableProperty } = require('../../../core/util')

class WebSocketError extends DOMException {
function createInheritableDOMException () {
// https://github.com/nodejs/node/issues/59677
class Test extends DOMException {
get reason () {
return ''
}
}

if (new Test().reason !== undefined) {
return DOMException
}

return new Proxy(DOMException, {
construct (target, args, newTarget) {
const instance = Reflect.construct(target, args, target)
Object.setPrototypeOf(instance, newTarget.prototype)
return instance
}
})
}

class WebSocketError extends createInheritableDOMException() {
#closeCode
#reason

Expand Down
Loading
Loading