diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml
index aaeef06aa..5c8529ad0 100644
--- a/.github/workflows/cypress.yml
+++ b/.github/workflows/cypress.yml
@@ -108,92 +108,3 @@ jobs:
name: cypress-screenshots-${{ matrix.package }}
path: packages/${{ matrix.package }}/typescript/cypress/screenshots
if-no-files-found: ignore
-
- test-itk-wasm-cypress:
- name: itk-wasm browser tests
- runs-on: ubuntu-24.04
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Free Disk Space (Ubuntu)
- uses: jlumbroso/free-disk-space@main
- with:
- large-packages: false
- tool-cache: true
-
- - name: Pull latest Docker images
- run: |
- ./src/docker/pull.sh --no-debug
-
- - name: Install
- uses: pnpm/action-setup@v4
-
- - uses: actions/setup-node@v4
- with:
- node-version: '22'
- cache: pnpm
- cache-dependency-path: ./pnpm-lock.yaml
-
- - name: Install node, cypress
- run: |
- pnpm install --frozen-lockfile
- pnpx cypress install
-
- - name: Build itk-wasm
- run: |
- pnpm run --aggregate-output --filter itk-wasm build
-
- - name: Build @itk-wasm/demo-app
- run: |
- pnpm run --aggregate-output --filter '@itk-wasm/demo-app' build
-
- - name: Build build:gen:typescript
- run: |
- pnpm run --aggregate-output build:gen:typescript
-
- - name: Build itk-wasm
- run: |
- pnpm run --aggregate-output --filter itk-wasm build
- # Test deps
- pnpm run --aggregate-output --filter "@itk-wasm/demo-app" build
- pnpm run --aggregate-output --filter "@itk-wasm/mesh-io" build
- pnpm run --aggregate-output --filter "@itk-wasm/transform-io" build
- pnpm run --aggregate-output --filter "@itk-wasm/image-io" build
-
- - name: Test itk-wasm with Chrome
- uses: cypress-io/github-action@v6
- with:
- browser: chrome
- working-directory: packages/core/typescript/itk-wasm
- install: false
- start: pnpm start
- config: video=true
- wait-on: 'http://localhost:5180'
- wait-on-timeout: 360
-
- - uses: actions/upload-artifact@v4
- if: always()
- with:
- name: cypress-videos
- path: packages/core/typescript/itk-wasm/cypress/videos
- if-no-files-found: ignore
-
- #- name: Test with Firefox
- #uses: cypress-io/github-action@v6
- #with:
- #browser: firefox
- #working-directory: packages/core/typescript/itk-wasm
- #install: false
- #config: video=true
- #start: pnpm start
- #wait-on: 'http://localhost:5180'
- #wait-on-timeout: 360
-
- - uses: actions/upload-artifact@v4
- if: failure()
- with:
- name: cypress-screenshots
- path: packages/core/typescript/itk-wasm/cypress/videos
- if-no-files-found: ignore
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 212b2d279..871d29c17 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -75,3 +75,68 @@ jobs:
name: playwright-report
path: playwright-report/
retention-days: 30
+
+ test-itk-wasm:
+ name: itk-wasm browser tests
+ runs-on: ubuntu-24.04
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Free Disk Space (Ubuntu)
+ uses: jlumbroso/free-disk-space@main
+ with:
+ large-packages: false
+ tool-cache: true
+
+ - name: Pull latest Docker images
+ run: |
+ ./src/docker/pull.sh --no-debug
+
+ - name: Install
+ uses: pnpm/action-setup@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '22'
+ cache: pnpm
+
+ - name: Install Playwright Browsers
+ run: pnpx playwright install --with-deps
+
+ - name: Install dependencies for itk-wasm
+ run: pnpm install
+ working-directory: packages/core/typescript/itk-wasm
+
+ - name: Build itk-wasm
+ run: |
+ pnpm run --aggregate-output --filter itk-wasm build
+
+ - name: Build @itk-wasm/demo-app
+ run: |
+ pnpm run --aggregate-output --filter '@itk-wasm/demo-app' build
+
+ - name: Build build:gen:typescript
+ run: |
+ pnpm run --aggregate-output build:gen:typescript
+
+ - name: Build itk-wasm
+ run: |
+ pnpm run --aggregate-output --filter itk-wasm build
+ # Test deps
+ pnpm run --aggregate-output --filter "@itk-wasm/demo-app" build
+ pnpm run --aggregate-output --filter "@itk-wasm/mesh-io" build
+ pnpm run --aggregate-output --filter "@itk-wasm/transform-io" build
+ pnpm run --aggregate-output --filter "@itk-wasm/image-io" build
+
+ - name: Run Playwright tests
+ working-directory: ./packages/core/typescript/itk-wasm
+ run: pnpm run test:browser
+
+ - uses: actions/upload-artifact@v4
+ if: ${{ !cancelled() }}
+ with:
+ name: playwright-report
+ path: packages/core/typescript/itk-wasm/playwright-report/
+ retention-days: 30
\ No newline at end of file
diff --git a/package.json b/package.json
index dca62b526..00c41597a 100644
--- a/package.json
+++ b/package.json
@@ -35,12 +35,13 @@
"devDependencies": {
"@changesets/cli": "^2.27.1",
"@commitlint/cli": "^19.3.0",
- "@commitlint/config-conventional": "^19.2.2"
+ "@commitlint/config-conventional": "^19.2.2",
+ "@playwright/test": "^1.53.0"
},
"pnpm": {
"overrides": {
"@shoelace-style/shoelace": "^2.12.0",
- "@types/node": "^22.13.13",
+ "@types/node": "^24.0.3",
"esbuild": "^0.25.1",
"start-server-and-test": "^2.0.12",
"ava": "^6.1.3",
diff --git a/packages/core/typescript/itk-wasm/.gitignore b/packages/core/typescript/itk-wasm/.gitignore
index e74b40ab7..c1493b006 100644
--- a/packages/core/typescript/itk-wasm/.gitignore
+++ b/packages/core/typescript/itk-wasm/.gitignore
@@ -3,4 +3,5 @@ test/pipelines/wasi-build
test/pipelines/typescript
test/pipelines/python
-cypress/screenshots
+playwright-report/
+test-results/
diff --git a/packages/core/typescript/itk-wasm/cypress.config.ts b/packages/core/typescript/itk-wasm/cypress.config.ts
deleted file mode 100644
index 0391b1710..000000000
--- a/packages/core/typescript/itk-wasm/cypress.config.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { defineConfig } from "cypress";
-
-export default defineConfig({
- projectId: '3ow3bt',
- e2e: {
- defaultCommandTimeout: 20000,
- baseUrl: "http://localhost:5180",
- setupNodeEvents(on, config) {
- // implement node event listeners here
- },
- includeShadowDom: true, // to query into itk-image-detail
- },
-});
diff --git a/packages/core/typescript/itk-wasm/cypress/e2e/cast-image.cy.ts b/packages/core/typescript/itk-wasm/cypress/e2e/cast-image.cy.ts
deleted file mode 100644
index 96453e15a..000000000
--- a/packages/core/typescript/itk-wasm/cypress/e2e/cast-image.cy.ts
+++ /dev/null
@@ -1,147 +0,0 @@
-import compareImageToBaseline from "../support/compareImageToBaseline"
-
-describe('castImage', () => {
- beforeEach(() => {
- cy.visit('/')
- })
-
-
- it('copies the input when no options are passed', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const inputImageType = new itk.ImageType()
- const inputImage = new itk.Image(inputImageType)
- inputImage.size = [256, 256]
- inputImage.data = new Uint8Array(256*256)
- inputImage.data.fill(7)
- inputImage.origin = [3.0, 4.0]
- inputImage.spacing = [9.0, 4.0]
- inputImage.direction[0] = -1.0
-
- const outputImage = itk.castImage(inputImage, {})
-
- compareImageToBaseline(itk, outputImage, inputImage)
- })
- })
-
-
- it('casts to the specified pixel type', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const inputImageType = new itk.ImageType()
- const inputImage = new itk.Image(inputImageType)
- inputImage.size = [256, 256]
- inputImage.data = new Uint8Array(256*256)
- inputImage.data.fill(7)
-
- const outputImage = itk.castImage(inputImage, { pixelType: itk.PixelTypes.CovariantVector })
-
- const baseline = inputImage
- baseline.imageType.pixelType = itk.PixelTypes.CovariantVector
-
- compareImageToBaseline(itk, outputImage, baseline)
- })
- })
-
-
- it('throws an error when casting a multi-component image to a scalar image', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const inputImageType = new itk.ImageType(2, itk.IntTypes.UInt8, itk.PixelTypes.Complex, 2)
- const inputImage = new itk.Image(inputImageType)
- inputImage.size = [256, 256]
- inputImage.data = new Uint8Array(256*256 * 2)
- inputImage.data.fill(7)
-
- expect(() => {
- itk.castImage(inputImage, { pixelType: itk.PixelTypes.Scalar })
- }).to.throw()
- })
- })
-
- it('casts to another TypedArray component type', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const inputImageType = new itk.ImageType()
- const inputImage = new itk.Image(inputImageType)
- inputImage.size = [256, 256]
- inputImage.data = new Uint8Array(256*256)
- inputImage.data.fill(7)
-
- const outputImage = itk.castImage(inputImage, { componentType: itk.FloatTypes.Float32 })
-
- const baseline = inputImage
- baseline.imageType.componentType = itk.FloatTypes.Float32
- baseline.data = new Float32Array(baseline.data)
-
- compareImageToBaseline(itk, outputImage, baseline)
- })
- })
-
- it('casts to a 64-bit integer component type', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const inputImageType = new itk.ImageType()
- const inputImage = new itk.Image(inputImageType)
- inputImage.size = [256, 256]
- inputImage.data = new Uint8Array(256*256)
- inputImage.data.fill(7)
-
- const outputImage = itk.castImage(inputImage, { componentType: itk.IntTypes.UInt64 })
-
- const baseline = inputImage
- baseline.imageType.componentType = itk.IntTypes.UInt64
- baseline.data = new BigUint64Array(baseline.data.length)
- baseline.data.fill(7n)
-
- compareImageToBaseline(itk, outputImage, baseline)
- })
- })
-
- it('casts from 64-bit to TypedArray component type', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const inputImageType = new itk.ImageType(2, itk.IntTypes.UInt64, itk.PixelTypes.Scalar, 1)
- const inputImage = new itk.Image(inputImageType)
- inputImage.size = [256, 256]
- inputImage.data = new BigUint64Array(256*256)
- inputImage.data.fill(7n)
-
- const outputImage = itk.castImage(inputImage, { componentType: itk.FloatTypes.Float32 })
-
- const baseline = inputImage
- baseline.imageType.componentType = itk.FloatTypes.Float32
- baseline.data = new Float32Array(baseline.data.length)
- baseline.data.fill(7)
-
- compareImageToBaseline(itk, outputImage, baseline)
- })
- })
-
- it('casts from 64-bit to another 64-bit integer component type', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const inputImageType = new itk.ImageType()
- const inputImage = new itk.Image(inputImageType)
- inputImage.size = [256, 256]
- inputImage.data = new BigInt64Array(256*256)
- inputImage.data.fill(7n)
-
- const outputImage = itk.castImage(inputImage, { componentType: itk.IntTypes.UInt64 })
-
- const baseline = inputImage
- baseline.imageType.componentType = itk.IntTypes.UInt64
- baseline.data = new BigUint64Array(baseline.data.length)
- baseline.data.fill(7n)
-
- compareImageToBaseline(itk, outputImage, baseline)
- })
- })
-})
diff --git a/packages/core/typescript/itk-wasm/cypress/e2e/pipeline/pthread-support-available.cy.ts b/packages/core/typescript/itk-wasm/cypress/e2e/pipeline/pthread-support-available.cy.ts
deleted file mode 100644
index 57c332046..000000000
--- a/packages/core/typescript/itk-wasm/cypress/e2e/pipeline/pthread-support-available.cy.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { demoServer, pipelineBaseUrl, pipelineWorkerUrl } from '../common'
-
-describe('pthreadSupportAvailable', () => {
- beforeEach(() => {
- cy.visit(demoServer)
- cy.window().then(async (win) => {
- const itk = win.itk
- itk.setPipelineWorkerUrl(pipelineWorkerUrl)
- itk.setPipelinesBaseUrl(pipelineBaseUrl)
- })
- })
-
- it('reports whether pthread support is available', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const pthreadSupportAvailable = itk.pthreadSupportAvailable()
- expect(pthreadSupportAvailable).to.equal(false)
- })
- })
-})
diff --git a/packages/core/typescript/itk-wasm/cypress/e2e/pipeline/run-pipeline.cy.ts b/packages/core/typescript/itk-wasm/cypress/e2e/pipeline/run-pipeline.cy.ts
deleted file mode 100644
index 460fe8ebc..000000000
--- a/packages/core/typescript/itk-wasm/cypress/e2e/pipeline/run-pipeline.cy.ts
+++ /dev/null
@@ -1,315 +0,0 @@
-import { readIwi, readIwm, demoServer, pipelineBaseUrl, pipelineWorkerUrl } from "../common"
-
-describe('runPipeline', () => {
- beforeEach(() => {
- cy.visit(demoServer)
- cy.window().then(async (win) => {
- const itk = win.itk
- itk.setPipelineWorkerUrl(pipelineWorkerUrl)
- itk.setPipelinesBaseUrl(pipelineBaseUrl)
- })
- })
-
- it('captures stdout and stderr', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const args = []
- const outputs = null
- const inputs = null
- const stdoutStderrPath = 'stdout-stderr-test'
- const { webWorker, returnValue, stdout, stderr } = await itk.runPipeline(stdoutStderrPath, args, outputs, inputs)
- })
- })
-
- it('fetches Wasm files from a custom URL', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const args = []
- const outputs = null
- const inputs = null
- const stdoutStderrPath = 'stdout-stderr-test'
- const { webWorker, returnValue, stdout, stderr } = await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, { pipelineBaseUrl, pipelineWorkerUrl })
- })
- })
-
- it('fetches Wasm files from a custom URL and query params', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const args = []
- const outputs = null
- const inputs = null
- const stdoutStderrPath = 'stdout-stderr-test'
- const { webWorker, returnValue, stdout, stderr } = await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, { pipelineBaseUrl, pipelineWorkerUrl, pipelineQueryParams: {key: 'value'} })
- })
- })
-
- it('fetches Wasm files from a custom pipelineBaseUrl string', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
- const pipelineBaseUrl = new URL('/pipelines', demoServer).href
-
- const args = []
- const outputs = null
- const inputs = null
- const stdoutStderrPath = 'stdout-stderr-test'
- const { webWorker, returnValue, stdout, stderr } = await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, { pipelineBaseUrl })
- })
- })
-
- it('fetches the pipeline web worker from a custom pipelineWorkerUrl string', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
- const pipelineWorkerUrl = new URL('/itk-wasm-pipeline.worker.js', demoServer).href
-
- const args = []
- const outputs = null
- const inputs = null
- const stdoutStderrPath = 'stdout-stderr-test'
- const { webWorker, returnValue, stdout, stderr } = await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, { pipelineWorkerUrl })
- })
- })
-
- it('uses a web worker created explicitly beforehand', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
- const pipelineWorkerUrl = new URL('/itk-wasm-pipeline.worker.js', demoServer).href
- const webWorker = await itk.createWebWorker(pipelineWorkerUrl)
-
- const args = []
- const outputs = null
- const inputs = null
- const stdoutStderrPath = 'stdout-stderr-test'
- const { returnValue, stdout, stderr } = await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, { webWorker })
- })
- })
-
- it('re-uses a WebWorker', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const args = []
- const outputs = null
- const inputs = null
- const stdoutStderrPath = 'stdout-stderr-test'
- const { webWorker } = await itk.runPipeline(stdoutStderrPath, args, outputs, inputs)
- const { returnValue, stdout, stderr } = await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, { webWorker })
- expect(typeof webWorker.terminated).to.equal('boolean')
- expect(webWorker.terminated).to.equal(false)
- webWorker.terminate()
- expect(webWorker.terminated).to.equal(true)
- expect(returnValue, 'returnValue').to.equal(0)
- expect(stdout, 'stdout').to.equal(`I’m writing my code,
-But I do not realize,
-Hours have gone by.
-`)
- expect(stderr, 'stderr').to.equal(`The modem humming
-Code rapidly compiling.
-Click. Perfect success.
-`)
- })
- })
-
-
- it('runs a pipeline on the main thread with an absolute URL', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const args = []
- const outputs = null
- const inputs = null
- const absoluteURL = new URL('/pipelines/stdout-stderr-test', document.location)
- const { returnValue, stdout, stderr } = await itk.runPipeline(absoluteURL, args, outputs, inputs, { webWorker: false })
- expect(returnValue, 'returnValue').to.equal(0)
- expect(stdout, 'stdout').to.equal(`I’m writing my code,
-But I do not realize,
-Hours have gone by.
-`)
- expect(stderr, 'stderr').to.equal(`The modem humming
-Code rapidly compiling.
-Click. Perfect success.
-`)
- })
- })
-
- it('uses input and output text and binary data via memory io', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const pipelinePath = 'input-output-files-test'
- const args = ['--memory-io',
- '--input-text-stream', '0',
- '--input-binary-stream', '1',
- '0',
- '1'
- ]
- const desiredOutputs = [
- { type: itk.InterfaceTypes.TextStream },
- { type: itk.InterfaceTypes.BinaryStream }
- ]
- const inputs = [
- { type: itk.InterfaceTypes.TextStream, data: { data: 'The answer is 42.' } },
- { type: itk.InterfaceTypes.BinaryStream, data: { data: new Uint8Array([222, 173, 190, 239]) } }
- ]
- const { stdout, stderr, outputs, webWorker } = await itk.runPipeline(pipelinePath, args, desiredOutputs, inputs)
- webWorker.terminate()
- expect(outputs[0].type, 'text output type').to.equal(itk.InterfaceTypes.TextStream)
- expect(outputs[0].data.data, 'text output data').to.equal('The answer is 42.')
- expect(outputs[1].type, 'binary output type').to.equal(itk.InterfaceTypes.BinaryStream)
- expect(outputs[1].data.data[0], 'binary output data[0]').to.equal(222)
- expect(outputs[1].data.data[1], 'binary output data[1]').to.equal(173)
- expect(outputs[1].data.data[2], 'binary output data[2]').to.equal(190)
- expect(outputs[1].data.data[3], 'binary output data[3]').to.equal(239)
- expect(stdout, 'stdout').to.equal(`Input text: The answer is 42.
-`)
- expect(stderr, 'stderr').to.equal(`Input binary: ffffffdeffffffadffffffbeffffffef
-`)
- })
- })
-
-
- it('runs on the main thread when webWorker option is false', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const pipelinePath = 'input-output-files-test'
- const args = ['--memory-io',
- '--input-text-stream', '0',
- '--input-binary-stream', '1',
- '0',
- '1'
- ]
- const desiredOutputs = [
- { type: itk.InterfaceTypes.TextStream },
- { type: itk.InterfaceTypes.BinaryStream }
- ]
- const inputs = [
- { type: itk.InterfaceTypes.TextStream, data: { data: 'The answer is 42.' } },
- { type: itk.InterfaceTypes.BinaryStream, data: { data: new Uint8Array([222, 173, 190, 239]) } }
- ]
- const { stdout, stderr, outputs } = await itk.runPipeline(pipelinePath, args, desiredOutputs, inputs, { webWorker: false })
- expect(outputs[0].type, 'text output type').to.equal(itk.InterfaceTypes.TextStream)
- expect(outputs[0].data.data, 'text output data').to.equal('The answer is 42.')
- expect(outputs[1].type, 'binary output type').to.equal(itk.InterfaceTypes.BinaryStream)
- expect(outputs[1].data.data[0], 'binary output data[0]').to.equal(222)
- expect(outputs[1].data.data[1], 'binary output data[1]').to.equal(173)
- expect(outputs[1].data.data[2], 'binary output data[2]').to.equal(190)
- expect(outputs[1].data.data[3], 'binary output data[3]').to.equal(239)
- expect(stdout, 'stdout').to.equal(`Input text: The answer is 42.
-`)
- expect(stderr, 'stderr').to.equal(`Input binary: ffffffdeffffffadffffffbeffffffef
-`)
- })
- })
-
- it('writes and reads itk.Image\'s', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const verifyImage = (image) => {
- expect(image.imageType.dimension, 'dimension').to.equal(2)
- expect(image.imageType.componentType, 'componentType').to.equal(itk.IntTypes.UInt8)
- expect(image.imageType.pixelType, 'pixelType').to.equal(itk.PixelTypes.Scalar)
- expect(image.imageType.components, 'components').to.equal(1)
- expect(image.origin, 'origin').to.deep.equal([0.0, 0.0])
- expect(image.spacing, 'spacing').to.deep.equal([1.0, 1.0])
- expect(image.size, 'size').to.deep.equal([256, 256])
- expect(image.data.byteLength, 'data.byteLength').to.equal(65536)
- }
-
- const cthead1BaseUrl = new URL('/data/cthead1.iwi/', demoServer).href
- const image = await readIwi(cthead1BaseUrl)
-
- const pipelinePath = 'median-filter-test'
- const args = [
- '0',
- '0',
- '--radius', '4',
- '--memory-io']
- const desiredOutputs = [
- { type: itk.InterfaceTypes.Image }
- ]
- const inputs = [
- { type: itk.InterfaceTypes.Image, data: image }
- ]
- const { webWorker, outputs } = await itk.runPipeline(pipelinePath, args, desiredOutputs, inputs)
- webWorker.terminate()
- verifyImage(outputs[0].data)
- })
- })
-
- it('runs twice without a detached buffer', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const verifyImage = (image) => {
- expect(image.imageType.dimension, 'dimension').to.equal(2)
- expect(image.imageType.componentType, 'componentType').to.equal(itk.IntTypes.UInt8)
- expect(image.imageType.pixelType, 'pixelType').to.equal(itk.PixelTypes.Scalar)
- expect(image.imageType.components, 'components').to.equal(1)
- expect(image.origin, 'origin').to.deep.equal([0.0, 0.0])
- expect(image.spacing, 'spacing').to.deep.equal([1.0, 1.0])
- expect(image.size, 'size').to.deep.equal([256, 256])
- expect(image.data.byteLength, 'data.byteLength').to.equal(65536)
- }
-
- const cthead1BaseUrl = new URL('/data/cthead1.iwi/', demoServer).href
- const image = await readIwi(cthead1BaseUrl)
-
- const pipelinePath = 'median-filter-test'
- const args = [
- '0',
- '0',
- '--radius', '4',
- '--memory-io']
- const desiredOutputs = [
- { type: itk.InterfaceTypes.Image }
- ]
- const inputs = [
- { type: itk.InterfaceTypes.Image, data: image }
- ]
- // const options = { noCopy: true } // failure expected
- const options = { noCopy: false }
- const { webWorker } = await itk.runPipeline(pipelinePath, args, desiredOutputs, inputs, options)
- options.webWorker = webWorker
- const { outputs } = await itk.runPipeline(pipelinePath, args, desiredOutputs, inputs, options)
- webWorker.terminate()
-
- verifyImage(outputs[0].data)
- })
- })
-
- it('runPipeline writes and reads an itk.Mesh via memory io', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
-
- const verifyMesh = (mesh) => {
- expect(mesh.meshType.dimension, 'dimension').to.equal(3)
- expect(mesh.meshType.pointComponentType, 'pointComponentType').to.equal(itk.FloatTypes.Float32)
- expect(mesh.meshType.cellComponentType, 'cellComponentType').to.equal(itk.IntTypes.UInt32)
- expect(mesh.meshType.pointPixelType, 'pointPixelType').to.equal(itk.PixelTypes.Scalar)
- expect(mesh.meshType.cellPixelType, 'cellPixelType').to.equal(itk.PixelTypes.Scalar)
- expect(mesh.numberOfPoints, 'numberOfPoints').to.equal(2903)
- expect(mesh.numberOfCells, 'numberOfCells').to.equal(3263)
- }
-
- const cowBaseUrl = new URL('/data/cow.iwm/', demoServer).href
- const mesh = await readIwm(cowBaseUrl)
-
- const pipelinePath = 'mesh-read-write-test'
- const args = ['0', '0', '--memory-io']
- const desiredOutputs = [
- { type: itk.InterfaceTypes.Mesh }
- ]
- const inputs = [
- { type: itk.InterfaceTypes.Mesh, data: mesh }
- ]
- const { webWorker, outputs } = await itk.runPipeline(pipelinePath, args, desiredOutputs, inputs)
- webWorker.terminate()
- verifyMesh(outputs[0].data)
- })
- })
-
-})
diff --git a/packages/core/typescript/itk-wasm/cypress/e2e/web-worker-pool.cy.ts b/packages/core/typescript/itk-wasm/cypress/e2e/web-worker-pool.cy.ts
deleted file mode 100644
index c76bc508e..000000000
--- a/packages/core/typescript/itk-wasm/cypress/e2e/web-worker-pool.cy.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { readIwi, demoServer, pipelineBaseUrl, pipelineWorkerUrl } from "./common"
-import compareImageToBaseline from "../support/compareImageToBaseline"
-
-describe('WebWorkerPool', () => {
- beforeEach(() => {
- cy.visit(demoServer)
- cy.window().then(async (win) => {
- const itk = win.itk
- itk.setPipelineWorkerUrl(pipelineWorkerUrl)
- itk.setPipelinesBaseUrl(pipelineBaseUrl)
- })
- })
-
- it('runs and reports progress', () => {
- cy.window().then(async (win) => {
- const itk = win.itk
- const progressUpdates = []
- let reportedTotalSplits = null
- function progressLogger (split, totalSplits) {
- progressUpdates.push(split)
- reportedTotalSplits = totalSplits
- }
-
- const poolSize = 2
- const maxTotalSplits = 4
- const workerPool = new itk.WorkerPool(poolSize, itk.runPipeline)
-
- const cthead1BaseUrl = new URL('/data/cthead1.iwi/', demoServer).href
- const image = await readIwi(cthead1BaseUrl)
-
- const taskArgsArray = []
- for (let index = 0; index < maxTotalSplits; index++) {
- const pipelinePath = 'median-filter-test'
- const args = ['--memory-io', '0', '0', '--radius', '4', '-m', '' + maxTotalSplits, '-s', '' + index]
- const desiredOutputs = [
- { type: itk.InterfaceTypes.Image }
- ]
- const data = itk.imageSharedBufferOrCopy(image)
- const inputs = [
- { type: itk.InterfaceTypes.Image, data }
- ]
- taskArgsArray.push([pipelinePath, args, desiredOutputs, inputs, {}])
- }
-
- const results = await workerPool.runTasks(taskArgsArray, progressLogger).promise
- workerPool.terminateWorkers()
-
- expect(reportedTotalSplits, 'reported total splits', maxTotalSplits)
- const imageSplits = results.map(({ outputs }) => outputs[0].data)
- const stackedImage = itk.stackImages(imageSplits)
-
- const baselineBaseUrl = new URL('/data/web-worker-pool-baseline.iwi/', demoServer).href
- const baselineImage = await readIwi(baselineBaseUrl)
-
- compareImageToBaseline(itk, stackedImage, baselineImage)
- })
- })
-})
diff --git a/packages/core/typescript/itk-wasm/cypress/support/commands.ts b/packages/core/typescript/itk-wasm/cypress/support/commands.ts
deleted file mode 100644
index 698b01a42..000000000
--- a/packages/core/typescript/itk-wasm/cypress/support/commands.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-///
-// ***********************************************
-// This example commands.ts shows you how to
-// create various custom commands and overwrite
-// existing commands.
-//
-// For more comprehensive examples of custom
-// commands please read more here:
-// https://on.cypress.io/custom-commands
-// ***********************************************
-//
-//
-// -- This is a parent command --
-// Cypress.Commands.add('login', (email, password) => { ... })
-//
-//
-// -- This is a child command --
-// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
-//
-//
-// -- This is a dual command --
-// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
-//
-//
-// -- This will overwrite an existing command --
-// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
-//
-// declare global {
-// namespace Cypress {
-// interface Chainable {
-// login(email: string, password: string): Chainable
-// drag(subject: string, options?: Partial): Chainable
-// dismiss(subject: string, options?: Partial): Chainable
-// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable
-// }
-// }
-// }
\ No newline at end of file
diff --git a/packages/core/typescript/itk-wasm/cypress/support/compareImageToBaseline.ts b/packages/core/typescript/itk-wasm/cypress/support/compareImageToBaseline.ts
deleted file mode 100644
index 757d24a6c..000000000
--- a/packages/core/typescript/itk-wasm/cypress/support/compareImageToBaseline.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-const compareImageToBaseline = (itk, testImage, baselineImage) => {
- expect(testImage.imageType, 'imageType').to.deep.equal(baselineImage.imageType)
- expect(testImage.origin, 'origin').to.deep.equal(baselineImage.origin)
- expect(testImage.spacing, 'spacing').to.deep.equal(baselineImage.spacing)
- expect(testImage.size, 'size').to.deep.equal(baselineImage.size)
- expect(testImage.data, 'data').to.deep.equal(baselineImage.data)
-}
-
-export default compareImageToBaseline
\ No newline at end of file
diff --git a/packages/core/typescript/itk-wasm/cypress/support/e2e.ts b/packages/core/typescript/itk-wasm/cypress/support/e2e.ts
deleted file mode 100644
index f80f74f8e..000000000
--- a/packages/core/typescript/itk-wasm/cypress/support/e2e.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-// ***********************************************************
-// This example support/e2e.ts is processed and
-// loaded automatically before your test files.
-//
-// This is a great place to put global configuration and
-// behavior that modifies Cypress.
-//
-// You can change the location of this file or turn off
-// automatically serving support files with the
-// 'supportFile' configuration option.
-//
-// You can read more here:
-// https://on.cypress.io/configuration
-// ***********************************************************
-
-// Import commands.js using ES2015 syntax:
-import './commands'
-
-// Alternatively you can use CommonJS syntax:
-// require('./commands')
\ No newline at end of file
diff --git a/packages/core/typescript/itk-wasm/cypress/tsconfig.json b/packages/core/typescript/itk-wasm/cypress/tsconfig.json
deleted file mode 100644
index 212405809..000000000
--- a/packages/core/typescript/itk-wasm/cypress/tsconfig.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "extends": "../tsconfig.json",
- "include": [
- "**/*.ts"
- ],
- "compilerOptions": {
- "noEmit": false,
- "sourceMap": false,
- "inlineSourceMap": true,
- "types": ["cypress"]
- },
-}
diff --git a/packages/core/typescript/itk-wasm/package.json b/packages/core/typescript/itk-wasm/package.json
index 9c628c3f0..f63ff6664 100644
--- a/packages/core/typescript/itk-wasm/package.json
+++ b/packages/core/typescript/itk-wasm/package.json
@@ -27,18 +27,11 @@
"build:workerBundle": "esbuild --bundle --format=esm --outfile=./dist/pipeline/web-workers/bundles/itk-wasm-pipeline.worker.js ./dist/pipeline/web-workers/itk-wasm-pipeline.worker.js",
"build:workerBundleForTesting": "esbuild --bundle --format=esm --outfile=./test/pipelines/typescript/test/browser/demo-app/public/itk-wasm-pipeline.worker.js ./dist/pipeline/web-workers/itk-wasm-pipeline.worker.js && shx cp -r ./test/data/ ./test/pipelines/typescript/test/browser/demo-app/public/",
"build:workerMinBundle": "esbuild --minify --bundle --format=esm --outfile=./dist/pipeline/web-workers/bundles/itk-wasm-pipeline.min.worker.js ./dist/pipeline/web-workers/itk-wasm-pipeline.worker.js",
- "cypress:open": "pnpm exec cypress open",
- "cypress:run": "pnpm exec cypress run --config defaultCommandTimeout=8000",
- "cypress:install": "pnpm exec cypress install",
- "cypress:runChrome": "pnpm exec cypress run --config defaultCommandTimeout=8000 --browser chrome",
- "cypress:runFirefox": "pnpm exec cypress run --config defaultCommandTimeout=8000 --browser firefox",
- "cypress:runFirefox:ci": "pnpm cypress:install && pnpm exec cypress run --config defaultCommandTimeout=8000 --browser firefox",
"start": "pnpm build:workerBundleForTesting && cd test/pipelines/typescript && pnpm build && pnpm start",
"test:wasi": "pnpm test:buildTestPipelines:wasi && pnpm test:runTestPipelines && pnpm test:bindgenTestPipelines:python",
- "test": "pnpm test:lint && pnpm test:testPipelines && pnpm test:node && pnpm test:bindgenTestPipelines:python && pnpm test:browser:chrome && pnpm test:browser:firefox",
+ "test": "pnpm test:lint && pnpm test:testPipelines && pnpm test:node && pnpm test:bindgenTestPipelines:python && pnpm test:browser",
"test:lint": "ts-standard --fix \"src/**/*.ts\" && standard --fix \"test/node/**/*.js\"",
"test:node": "ava test/node/**/*.js",
- "test:browser": "pnpm run test:browser:chrome && pnpm run test:browser:firefox",
"test:testPipelines": "pnpm test:buildTestPipelines:emscripten && pnpm test:buildTestPipelines:wasi && pnpm test:runTestPipelines",
"test:buildTestPipelines:emscripten:debug": "node src/itk-wasm-cli.js -i quay.io/itkwasm/emscripten:latest-debug -b emscripten-build -s ./test/pipelines build -- -DCMAKE_BUILD_TYPE=Debug",
"test:buildTestPipelines:emscripten": "node src/itk-wasm-cli.js -i quay.io/itkwasm/emscripten:latest -b emscripten-build -s ./test/pipelines build",
@@ -49,11 +42,9 @@
"test:runTestPipelines": "node src/itk-wasm-cli.js -i quay.io/itkwasm/wasi:latest -b wasi-build -s ./test/pipelines run -r wasmtime stdout-stderr-pipeline/stdout-stderr-test.wasi.wasm",
"test:bindgenTestPipelines:typescript": "node src/itk-wasm-cli.js -i quay.io/itkwasm/emscripten:latest -b emscripten-build -s ./test/pipelines/ bindgen --package-version 1.0.0 --package-name test-pipelines --package-description \"Exercise interface types for bindgen\"",
"test:bindgenTestPipelines:python": "node src/itk-wasm-cli.js -i quay.io/itkwasm/wasi:latest -b wasi-build -s ./test/pipelines/ bindgen --interface python --package-version 1.0.0 --package-name test-pipelines --package-description \"Exercise interface types for bindgen\"",
- "test:browser:debug": "start-server-and-test start http-get://localhost:5180 cypress:open",
- "test:cypress": "start-server-and-test start http-get://localhost:5180 cypress:run",
- "test:browser:chrome": "start-server-and-test start http-get://localhost:5180 cypress:runChrome",
- "test:browser:firefox:ci": "start-server-and-test start http-get://localhost:5180 cypress:runFirefox:ci",
- "test:browser:firefox": "start-server-and-test start http-get://localhost:5180 cypress:runFirefox",
+ "test:browser": "playwright test",
+ "test:browser:ui": "playwright test --ui",
+ "test:browser:debug": "playwright test --debug",
"prepublishOnly": "pnpm build:tsc && node ./src/update-versions.cjs && pnpm build:workerBundle && pnpm build:workerMinBundle && pnpm build:bundle && pnpm build:minBundle",
"clean": "git clean -fdx"
},
@@ -78,15 +69,14 @@
},
"homepage": "https://wasm.itk.org/",
"devDependencies": {
- "@types/node": "^20.10.3",
+ "@playwright/test": "^1.53.0",
+ "@types/node": "^22.13.13",
"ava": "^5.3.1",
- "cypress": "^13.7.3",
"esbuild": "^0.25.0",
"prettier": "^3.2.5",
"prettier-config-standard": "^7.0.0",
"shx": "^0.3.4",
"standard": "^17.1.0",
- "start-server-and-test": "^2.0.3",
"ts-standard": "^12.0.2",
"typescript": "^5.3.2"
},
diff --git a/packages/core/typescript/itk-wasm/playwright.config.js b/packages/core/typescript/itk-wasm/playwright.config.js
new file mode 100644
index 000000000..76c95b398
--- /dev/null
+++ b/packages/core/typescript/itk-wasm/playwright.config.js
@@ -0,0 +1,81 @@
+// @ts-check
+import { defineConfig, devices } from '@playwright/test'
+
+/**
+ * Read environment variables from file.
+ * https://github.com/motdotla/dotenv
+ */
+// import dotenv from 'dotenv';
+// import path from 'path';
+// dotenv.config({ path: path.resolve(__dirname, '.env') });
+
+/**
+ * @see https://playwright.dev/docs/test-configuration
+ */
+export default defineConfig({
+ testDir: './test/browser',
+ testMatch: '**/*.spec.js',
+ /* Run tests in files in parallel */
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: 'html',
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ baseURL: 'http://localhost:5180',
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: 'on-first-retry'
+ },
+
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] }
+ },
+
+ {
+ name: 'firefox',
+ use: { ...devices['Desktop Firefox'] }
+ },
+
+ {
+ name: 'webkit',
+ use: { ...devices['Desktop Safari'] }
+ }
+
+ /* Test against mobile viewports. */
+ // {
+ // name: 'Mobile Chrome',
+ // use: { ...devices['Pixel 5'] },
+ // },
+ // {
+ // name: 'Mobile Safari',
+ // use: { ...devices['iPhone 12'] },
+ // },
+
+ /* Test against branded browsers. */
+ // {
+ // name: 'Microsoft Edge',
+ // use: { ...devices['Desktop Edge'], channel: 'msedge' },
+ // },
+ // {
+ // name: 'Google Chrome',
+ // use: { ...devices['Desktop Chrome'], channel: 'chrome' },
+ // },
+ ],
+
+ /* Run your local dev server before starting the tests */
+ webServer: {
+ command: 'pnpm run start',
+ url: 'http://localhost:5180',
+ reuseExistingServer: !process.env.CI
+ }
+})
diff --git a/packages/core/typescript/itk-wasm/test/browser/cast-image.spec.js b/packages/core/typescript/itk-wasm/test/browser/cast-image.spec.js
new file mode 100644
index 000000000..67b413927
--- /dev/null
+++ b/packages/core/typescript/itk-wasm/test/browser/cast-image.spec.js
@@ -0,0 +1,199 @@
+import { test, expect } from '@playwright/test'
+import compareImageToBaseline from './compare-image-to-baseline.js'
+
+test.describe('castImage', () => {
+ test.beforeEach(async ({ page }) => {
+ await page.goto('/')
+ })
+
+ test('copies the input when no options are passed', async ({ page }) => {
+ const { outputImage, inputImage: baseline } = await page.evaluate(() => {
+ const itk = window.itk
+
+ const inputImageType = new itk.ImageType()
+ const inputImage = new itk.Image(inputImageType)
+ inputImage.size = [256, 256]
+ inputImage.data = new Uint8Array(256 * 256)
+ inputImage.data.fill(7)
+ inputImage.origin = [3.0, 4.0]
+ inputImage.spacing = [9.0, 4.0]
+ inputImage.direction.set([-1.0, 0.0, 0.0, -1.0]) // Assuming 2D, ensure full direction matrix
+
+ const outputImage = itk.castImage(inputImage, {})
+
+ // Return both for comparison
+ return {
+ outputImage: JSON.parse(JSON.stringify(outputImage)),
+ inputImage: JSON.parse(JSON.stringify(inputImage))
+ }
+ })
+
+ compareImageToBaseline(outputImage, baseline)
+ })
+
+ test('casts to the specified pixel type', async ({ page }) => {
+ const { outputImage, baseline } = await page.evaluate(() => {
+ const itk = window.itk
+
+ const inputImageType = new itk.ImageType()
+ const inputImage = new itk.Image(inputImageType)
+ inputImage.size = [256, 256]
+ inputImage.data = new Uint8Array(256 * 256)
+ inputImage.data.fill(7)
+ // Ensure other properties are set if compareImageToBaseline checks them
+ inputImage.origin = [0.0, 0.0]
+ inputImage.spacing = [1.0, 1.0]
+ inputImage.direction.set([1.0, 0.0, 0.0, 1.0])
+
+ const outputImage = itk.castImage(inputImage, {
+ pixelType: itk.PixelTypes.CovariantVector
+ })
+
+ const baseline = JSON.parse(JSON.stringify(inputImage)) // Deep copy
+ baseline.imageType.pixelType = itk.PixelTypes.CovariantVector
+ // Data itself doesn't change type here, just the interpretation if components > 1
+ // If compareImageToBaseline relies on data type, this might need adjustment
+ // For CovariantVector with 1 component, data remains the same.
+
+ return { outputImage: JSON.parse(JSON.stringify(outputImage)), baseline }
+ })
+
+ compareImageToBaseline(outputImage, baseline)
+ })
+
+ test('throws an error when casting a multi-component image to a scalar image', async ({
+ page
+ }) => {
+ const errorOccurred = await page.evaluate(() => {
+ const itk = window.itk
+
+ const inputImageType = new itk.ImageType(
+ 2,
+ itk.IntTypes.UInt8,
+ itk.PixelTypes.Complex,
+ 2
+ )
+ const inputImage = new itk.Image(inputImageType)
+ inputImage.size = [256, 256]
+ inputImage.data = new Uint8Array(256 * 256 * 2 * 2) // Complex has 2 components, and components=2
+ inputImage.data.fill(7)
+ // Ensure other properties are set
+ inputImage.origin = [0.0, 0.0]
+ inputImage.spacing = [1.0, 1.0]
+ inputImage.direction.set([1.0, 0.0, 0.0, 1.0])
+
+ try {
+ itk.castImage(inputImage, { pixelType: itk.PixelTypes.Scalar })
+ return false // Should not reach here
+ } catch (e) {
+ return true
+ }
+ })
+ expect(errorOccurred).toBe(true)
+ })
+
+ test('casts to another TypedArray component type', async ({ page }) => {
+ const { outputImage, baseline } = await page.evaluate(() => {
+ const itk = window.itk
+
+ const inputImageType = new itk.ImageType()
+ const inputImage = new itk.Image(inputImageType)
+ inputImage.size = [256, 256]
+ inputImage.data = new Uint8Array(256 * 256)
+ inputImage.data.fill(7)
+
+ const outputImage = itk.castImage(inputImage, {
+ componentType: itk.FloatTypes.Float32
+ })
+
+ const baseline = inputImage
+ baseline.imageType.componentType = itk.FloatTypes.Float32
+ baseline.data = new Float32Array(baseline.data)
+
+ return { outputImage, baseline }
+ })
+
+ compareImageToBaseline(outputImage, baseline)
+ })
+
+ test('casts to a 64-bit integer component type', async ({ page }) => {
+ const { outputImage, baseline } = await page.evaluate(() => {
+ const itk = window.itk
+
+ const inputImageType = new itk.ImageType()
+ const inputImage = new itk.Image(inputImageType)
+ inputImage.size = [256, 256]
+ inputImage.data = new Uint8Array(256 * 256)
+ inputImage.data.fill(7)
+
+ const outputImage = itk.castImage(inputImage, {
+ componentType: itk.IntTypes.UInt64
+ })
+
+ const baseline = inputImage
+ baseline.imageType.componentType = itk.IntTypes.UInt64
+ baseline.data = new BigUint64Array(baseline.data.length)
+ baseline.data.fill(7n)
+
+ return { outputImage, baseline }
+ })
+
+ compareImageToBaseline(outputImage, baseline)
+ })
+
+ test('casts from 64-bit to TypedArray component type', async ({ page }) => {
+ const { outputImage, baseline } = await page.evaluate(() => {
+ const itk = window.itk
+
+ const inputImageType = new itk.ImageType(
+ 2,
+ itk.IntTypes.UInt64,
+ itk.PixelTypes.Scalar,
+ 1
+ )
+ const inputImage = new itk.Image(inputImageType)
+ inputImage.size = [256, 256]
+ inputImage.data = new BigUint64Array(256 * 256)
+ inputImage.data.fill(7n)
+
+ const outputImage = itk.castImage(inputImage, {
+ componentType: itk.FloatTypes.Float32
+ })
+
+ const baseline = inputImage
+ baseline.imageType.componentType = itk.FloatTypes.Float32
+ baseline.data = new Float32Array(baseline.data.length)
+ baseline.data.fill(7)
+
+ return { outputImage, baseline }
+ })
+
+ compareImageToBaseline(outputImage, baseline)
+ })
+
+ test('casts from 64-bit to another 64-bit integer component type', async ({
+ page
+ }) => {
+ const { outputImage, baseline } = await page.evaluate(() => {
+ const itk = window.itk
+
+ const inputImageType = new itk.ImageType()
+ const inputImage = new itk.Image(inputImageType)
+ inputImage.size = [256, 256]
+ inputImage.data = new BigInt64Array(256 * 256)
+ inputImage.data.fill(7n)
+
+ const outputImage = itk.castImage(inputImage, {
+ componentType: itk.IntTypes.UInt64
+ })
+
+ const baseline = inputImage
+ baseline.imageType.componentType = itk.IntTypes.UInt64
+ baseline.data = new BigUint64Array(baseline.data.length)
+ baseline.data.fill(7n)
+
+ return { outputImage, baseline }
+ })
+ compareImageToBaseline(outputImage, baseline)
+ })
+})
diff --git a/packages/core/typescript/itk-wasm/cypress/e2e/common.ts b/packages/core/typescript/itk-wasm/test/browser/common.js
similarity index 78%
rename from packages/core/typescript/itk-wasm/cypress/e2e/common.ts
rename to packages/core/typescript/itk-wasm/test/browser/common.js
index 12fadf2c4..ba1f6f657 100644
--- a/packages/core/typescript/itk-wasm/cypress/e2e/common.ts
+++ b/packages/core/typescript/itk-wasm/test/browser/common.js
@@ -1,9 +1,7 @@
-export const demoServer = 'http://localhost:5180'
+export const pipelineBaseUrl = '/pipelines'
+export const pipelineWorkerUrl = '/itk-wasm-pipeline.worker.js'
-export const pipelineBaseUrl = new URL('/pipelines', demoServer)
-export const pipelineWorkerUrl = new URL('/itk-wasm-pipeline.worker.js', demoServer)
-
-export async function readIwi(baseUrl: string) {
+export async function readIwi(baseUrl) {
const imageResponse = await fetch(`${baseUrl}index.json`)
const image = await imageResponse.json()
const directionResponse = await fetch(`${baseUrl}data/direction.raw`)
@@ -17,7 +15,7 @@ export async function readIwi(baseUrl: string) {
return image
}
-export async function readIwm (baseUrl: string) {
+export async function readIwm(baseUrl) {
const meshResponse = await fetch(`${baseUrl}index.json`)
const mesh = await meshResponse.json()
const pointsResponse = await fetch(`${baseUrl}data/points.raw`)
diff --git a/packages/core/typescript/itk-wasm/test/browser/compare-image-to-baseline.js b/packages/core/typescript/itk-wasm/test/browser/compare-image-to-baseline.js
new file mode 100644
index 000000000..25e2737c8
--- /dev/null
+++ b/packages/core/typescript/itk-wasm/test/browser/compare-image-to-baseline.js
@@ -0,0 +1,12 @@
+import { expect } from '@playwright/test'
+
+const compareImageToBaseline = (testImage, baselineImage) => {
+ expect(testImage.imageType).toEqual(baselineImage.imageType)
+ expect(testImage.origin).toEqual(baselineImage.origin)
+ expect(testImage.spacing).toEqual(baselineImage.spacing)
+ expect(testImage.direction).toEqual(baselineImage.direction)
+ expect(testImage.size).toEqual(baselineImage.size)
+ expect(testImage.data).toEqual(baselineImage.data)
+}
+
+export default compareImageToBaseline
diff --git a/packages/core/typescript/itk-wasm/test/browser/pipeline/pthread-support-available.spec.js b/packages/core/typescript/itk-wasm/test/browser/pipeline/pthread-support-available.spec.js
new file mode 100644
index 000000000..e64f39f49
--- /dev/null
+++ b/packages/core/typescript/itk-wasm/test/browser/pipeline/pthread-support-available.spec.js
@@ -0,0 +1,26 @@
+import { test, expect } from '@playwright/test'
+import { pipelineBaseUrl, pipelineWorkerUrl } from '../common.js'
+
+test.describe('pthreadSupportAvailable', () => {
+ test('reports whether pthread support is available', async ({
+ page,
+ browserName
+ }) => {
+ test.skip(browserName === 'webkit', 'Flaky on webkit')
+
+ await page.goto('/')
+
+ const pthreadSupportAvailable = await page.evaluate(
+ async ({ pipelineWorkerUrl, pipelineBaseUrl }) => {
+ const itk = window.itk
+ itk.setPipelineWorkerUrl(pipelineWorkerUrl)
+ itk.setPipelinesBaseUrl(pipelineBaseUrl)
+
+ return itk.pthreadSupportAvailable()
+ },
+ { pipelineWorkerUrl, pipelineBaseUrl }
+ )
+
+ expect(pthreadSupportAvailable).toBe(true)
+ })
+})
diff --git a/packages/core/typescript/itk-wasm/test/browser/pipeline/run-pipeline.spec.js b/packages/core/typescript/itk-wasm/test/browser/pipeline/run-pipeline.spec.js
new file mode 100644
index 000000000..0b071d97d
--- /dev/null
+++ b/packages/core/typescript/itk-wasm/test/browser/pipeline/run-pipeline.spec.js
@@ -0,0 +1,502 @@
+import { test, expect } from '@playwright/test'
+import { pipelineBaseUrl, pipelineWorkerUrl } from '../common.js'
+
+test.describe('runPipeline', () => {
+ test.beforeEach(async ({ page }) => {
+ await page.goto('/')
+ await page.evaluate(
+ ({ pipelineWorkerUrl, pipelineBaseUrl }) => {
+ const itk = window.itk
+ itk.setPipelineWorkerUrl(pipelineWorkerUrl)
+ itk.setPipelinesBaseUrl(pipelineBaseUrl)
+ },
+ { pipelineWorkerUrl, pipelineBaseUrl }
+ )
+ })
+
+ test('captures stdout and stderr', async ({ page }) => {
+ await page.evaluate(async () => {
+ const itk = window.itk
+
+ const args = []
+ const outputs = null
+ const inputs = null
+ const stdoutStderrPath = 'stdout-stderr-test'
+ await itk.runPipeline(stdoutStderrPath, args, outputs, inputs)
+ })
+ })
+
+ test('fetches Wasm files from a custom URL', async ({ page }) => {
+ await page.evaluate(
+ async ({ pipelineBaseUrl, pipelineWorkerUrl }) => {
+ const itk = window.itk
+
+ const args = []
+ const outputs = null
+ const inputs = null
+ const stdoutStderrPath = 'stdout-stderr-test'
+ await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, {
+ pipelineBaseUrl,
+ pipelineWorkerUrl
+ })
+ },
+ { pipelineBaseUrl, pipelineWorkerUrl }
+ )
+ })
+
+ test('fetches Wasm files from a custom URL and query params', async ({
+ page
+ }) => {
+ await page.evaluate(
+ async ({ pipelineBaseUrl, pipelineWorkerUrl }) => {
+ const itk = window.itk
+
+ const args = []
+ const outputs = null
+ const inputs = null
+ const stdoutStderrPath = 'stdout-stderr-test'
+ await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, {
+ pipelineBaseUrl,
+ pipelineWorkerUrl,
+ pipelineQueryParams: { key: 'value' }
+ })
+ },
+ { pipelineBaseUrl, pipelineWorkerUrl }
+ )
+ })
+
+ test('fetches Wasm files from a custom pipelineBaseUrl string', async ({
+ page
+ }) => {
+ await page.evaluate(async () => {
+ const itk = window.itk
+ const pipelineBaseUrl = '/pipelines'
+
+ const args = []
+ const outputs = null
+ const inputs = null
+ const stdoutStderrPath = 'stdout-stderr-test'
+ await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, {
+ pipelineBaseUrl
+ })
+ })
+ })
+
+ test('fetches the pipeline web worker from a custom pipelineWorkerUrl string', async ({
+ page
+ }) => {
+ await page.evaluate(async () => {
+ const itk = window.itk
+ const pipelineWorkerUrl = '/itk-wasm-pipeline.worker.js'
+
+ const args = []
+ const outputs = null
+ const inputs = null
+ const stdoutStderrPath = 'stdout-stderr-test'
+ await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, {
+ pipelineWorkerUrl
+ })
+ })
+ })
+
+ test('uses a web worker created explicitly beforehand', async ({ page }) => {
+ await page.evaluate(async () => {
+ const itk = window.itk
+ const pipelineWorkerUrl = '/itk-wasm-pipeline.worker.js'
+ const webWorker = await itk.createWebWorker(pipelineWorkerUrl)
+
+ const args = []
+ const outputs = null
+ const inputs = null
+ const stdoutStderrPath = 'stdout-stderr-test'
+ await itk.runPipeline(stdoutStderrPath, args, outputs, inputs, {
+ webWorker
+ })
+ })
+ })
+
+ test('re-uses a WebWorker', async ({ page }) => {
+ const result = await page.evaluate(async () => {
+ const itk = window.itk
+
+ const args = []
+ const outputs = null
+ const inputs = null
+ const stdoutStderrPath = 'stdout-stderr-test'
+ const { webWorker } = await itk.runPipeline(
+ stdoutStderrPath,
+ args,
+ outputs,
+ inputs
+ )
+ const { returnValue, stdout, stderr } = await itk.runPipeline(
+ stdoutStderrPath,
+ args,
+ outputs,
+ inputs,
+ { webWorker }
+ )
+
+ const terminatedBefore = webWorker.terminated
+ webWorker.terminate()
+ const terminatedAfter = webWorker.terminated
+
+ return {
+ terminatedBefore,
+ terminatedAfter,
+ returnValue,
+ stdout,
+ stderr
+ }
+ })
+
+ expect(typeof result.terminatedBefore).toBe('boolean')
+ expect(result.terminatedBefore).toBe(false)
+ expect(result.terminatedAfter).toBe(true)
+ expect(result.returnValue).toBe(0)
+ expect(result.stdout).toBe(`I’m writing my code,
+But I do not realize,
+Hours have gone by.
+`)
+ expect(result.stderr).toBe(`The modem humming
+Code rapidly compiling.
+Click. Perfect success.
+`)
+ })
+
+ test('runs a pipeline on the main thread with an absolute URL', async ({
+ page
+ }) => {
+ const result = await page.evaluate(async () => {
+ const itk = window.itk
+
+ const args = []
+ const outputs = null
+ const inputs = null
+ const absoluteURL = new URL(
+ '/pipelines/stdout-stderr-test',
+ document.location
+ )
+ const { returnValue, stdout, stderr } = await itk.runPipeline(
+ absoluteURL,
+ args,
+ outputs,
+ inputs,
+ { webWorker: false }
+ )
+
+ return { returnValue, stdout, stderr }
+ })
+
+ expect(result.returnValue).toBe(0)
+ expect(result.stdout).toBe(`I’m writing my code,
+But I do not realize,
+Hours have gone by.
+`)
+ expect(result.stderr).toBe(`The modem humming
+Code rapidly compiling.
+Click. Perfect success.
+`)
+ })
+
+ test('uses input and output text and binary data via memory io', async ({
+ page
+ }) => {
+ const result = await page.evaluate(async () => {
+ const itk = window.itk
+
+ const pipelinePath = 'input-output-files-test'
+ const args = [
+ '--memory-io',
+ '--input-text-stream',
+ '0',
+ '--input-binary-stream',
+ '1',
+ '0',
+ '1'
+ ]
+ const desiredOutputs = [
+ { type: itk.InterfaceTypes.TextStream },
+ { type: itk.InterfaceTypes.BinaryStream }
+ ]
+ const inputs = [
+ {
+ type: itk.InterfaceTypes.TextStream,
+ data: { data: 'The answer is 42.' }
+ },
+ {
+ type: itk.InterfaceTypes.BinaryStream,
+ data: { data: new Uint8Array([222, 173, 190, 239]) }
+ }
+ ]
+ const { stdout, stderr, outputs, webWorker } = await itk.runPipeline(
+ pipelinePath,
+ args,
+ desiredOutputs,
+ inputs
+ )
+ webWorker.terminate()
+
+ return {
+ outputs: outputs.map((output) => ({
+ type: output.type,
+ data: output.data
+ })),
+ stdout,
+ stderr
+ }
+ })
+
+ expect(result.outputs[0].type).toBe('TextStream')
+ expect(result.outputs[0].data.data).toBe('The answer is 42.')
+ expect(result.outputs[1].type).toBe('BinaryStream')
+ expect(result.outputs[1].data.data[0]).toBe(222)
+ expect(result.outputs[1].data.data[1]).toBe(173)
+ expect(result.outputs[1].data.data[2]).toBe(190)
+ expect(result.outputs[1].data.data[3]).toBe(239)
+ expect(result.stdout).toBe(`Input text: The answer is 42.
+`)
+ expect(result.stderr).toBe(`Input binary: ffffffdeffffffadffffffbeffffffef
+`)
+ })
+
+ test('runs on the main thread when webWorker option is false', async ({
+ page
+ }) => {
+ const result = await page.evaluate(async () => {
+ const itk = window.itk
+
+ const pipelinePath = 'input-output-files-test'
+ const args = [
+ '--memory-io',
+ '--input-text-stream',
+ '0',
+ '--input-binary-stream',
+ '1',
+ '0',
+ '1'
+ ]
+ const desiredOutputs = [
+ { type: itk.InterfaceTypes.TextStream },
+ { type: itk.InterfaceTypes.BinaryStream }
+ ]
+ const inputs = [
+ {
+ type: itk.InterfaceTypes.TextStream,
+ data: { data: 'The answer is 42.' }
+ },
+ {
+ type: itk.InterfaceTypes.BinaryStream,
+ data: { data: new Uint8Array([222, 173, 190, 239]) }
+ }
+ ]
+ const { stdout, stderr, outputs } = await itk.runPipeline(
+ pipelinePath,
+ args,
+ desiredOutputs,
+ inputs,
+ { webWorker: false }
+ )
+
+ return {
+ outputs: outputs.map((output) => ({
+ type: output.type,
+ data: output.data
+ })),
+ stdout,
+ stderr
+ }
+ })
+
+ expect(result.outputs[0].type).toBe('TextStream')
+ expect(result.outputs[0].data.data).toBe('The answer is 42.')
+ expect(result.outputs[1].type).toBe('BinaryStream')
+ expect(result.outputs[1].data.data[0]).toBe(222)
+ expect(result.outputs[1].data.data[1]).toBe(173)
+ expect(result.outputs[1].data.data[2]).toBe(190)
+ expect(result.outputs[1].data.data[3]).toBe(239)
+ expect(result.stdout).toBe(`Input text: The answer is 42.
+`)
+ expect(result.stderr).toBe(`Input binary: ffffffdeffffffadffffffbeffffffef
+`)
+ })
+
+ test("writes and reads itk.Image's", async ({ page }) => {
+ await page.evaluate(async () => {
+ const itk = window.itk
+
+ const verifyImage = (image) => {
+ if (image.imageType.dimension !== 2)
+ throw new Error('dimension mismatch')
+ if (image.imageType.componentType !== itk.IntTypes.UInt8)
+ throw new Error('componentType mismatch')
+ if (image.imageType.pixelType !== itk.PixelTypes.Scalar)
+ throw new Error('pixelType mismatch')
+ if (image.imageType.components !== 1)
+ throw new Error('components mismatch')
+ if (JSON.stringify(image.origin) !== JSON.stringify([0.0, 0.0]))
+ throw new Error('origin mismatch')
+ if (JSON.stringify(image.spacing) !== JSON.stringify([1.0, 1.0]))
+ throw new Error('spacing mismatch')
+ if (JSON.stringify(image.size) !== JSON.stringify([256, 256]))
+ throw new Error('size mismatch')
+ if (image.data.byteLength !== 65536)
+ throw new Error('data.byteLength mismatch')
+ }
+
+ const readIwi = async (baseUrl) => {
+ const imageResponse = await fetch(`${baseUrl}index.json`)
+ const image = await imageResponse.json()
+ const directionResponse = await fetch(`${baseUrl}data/direction.raw`)
+ const directionBuffer = await directionResponse.arrayBuffer()
+ const directionData = new Float64Array(directionBuffer)
+ image.direction = directionData
+ const dataResponse = await fetch(`${baseUrl}data/data.raw`)
+ const dataBuffer = await dataResponse.arrayBuffer()
+ const pixelData = new Uint8Array(dataBuffer)
+ image.data = pixelData
+ return image
+ }
+
+ const cthead1BaseUrl = '/data/cthead1.iwi/'
+ const image = await readIwi(cthead1BaseUrl)
+
+ const pipelinePath = 'median-filter-test'
+ const args = ['0', '0', '--radius', '4', '--memory-io']
+ const desiredOutputs = [{ type: itk.InterfaceTypes.Image }]
+ const inputs = [{ type: itk.InterfaceTypes.Image, data: image }]
+ const { webWorker, outputs } = await itk.runPipeline(
+ pipelinePath,
+ args,
+ desiredOutputs,
+ inputs
+ )
+ webWorker.terminate()
+ verifyImage(outputs[0].data)
+ })
+ })
+
+ test('runs twice without a detached buffer', async ({ page }) => {
+ await page.evaluate(async () => {
+ const itk = window.itk
+
+ const verifyImage = (image) => {
+ if (image.imageType.dimension !== 2)
+ throw new Error('dimension mismatch')
+ if (image.imageType.componentType !== itk.IntTypes.UInt8)
+ throw new Error('componentType mismatch')
+ if (image.imageType.pixelType !== itk.PixelTypes.Scalar)
+ throw new Error('pixelType mismatch')
+ if (image.imageType.components !== 1)
+ throw new Error('components mismatch')
+ if (JSON.stringify(image.origin) !== JSON.stringify([0.0, 0.0]))
+ throw new Error('origin mismatch')
+ if (JSON.stringify(image.spacing) !== JSON.stringify([1.0, 1.0]))
+ throw new Error('spacing mismatch')
+ if (JSON.stringify(image.size) !== JSON.stringify([256, 256]))
+ throw new Error('size mismatch')
+ if (image.data.byteLength !== 65536)
+ throw new Error('data.byteLength mismatch')
+ }
+
+ const readIwi = async (baseUrl) => {
+ const imageResponse = await fetch(`${baseUrl}index.json`)
+ const image = await imageResponse.json()
+ const directionResponse = await fetch(`${baseUrl}data/direction.raw`)
+ const directionBuffer = await directionResponse.arrayBuffer()
+ const directionData = new Float64Array(directionBuffer)
+ image.direction = directionData
+ const dataResponse = await fetch(`${baseUrl}data/data.raw`)
+ const dataBuffer = await dataResponse.arrayBuffer()
+ const pixelData = new Uint8Array(dataBuffer)
+ image.data = pixelData
+ return image
+ }
+
+ const cthead1BaseUrl = '/data/cthead1.iwi/'
+ const image = await readIwi(cthead1BaseUrl)
+
+ const pipelinePath = 'median-filter-test'
+ const args = ['0', '0', '--radius', '4', '--memory-io']
+ const desiredOutputs = [{ type: itk.InterfaceTypes.Image }]
+ const inputs = [{ type: itk.InterfaceTypes.Image, data: image }]
+ // const options = { noCopy: true } // failure expected
+ const options = { noCopy: false }
+ const { webWorker } = await itk.runPipeline(
+ pipelinePath,
+ args,
+ desiredOutputs,
+ inputs,
+ options
+ )
+ options.webWorker = webWorker
+ const { outputs } = await itk.runPipeline(
+ pipelinePath,
+ args,
+ desiredOutputs,
+ inputs,
+ options
+ )
+ webWorker.terminate()
+
+ verifyImage(outputs[0].data)
+ })
+ })
+
+ test('runPipeline writes and reads an itk.Mesh via memory io', async ({
+ page
+ }) => {
+ await page.evaluate(async () => {
+ const itk = window.itk
+
+ const verifyMesh = (mesh) => {
+ if (mesh.meshType.dimension !== 3) throw new Error('dimension mismatch')
+ if (mesh.meshType.pointComponentType !== itk.FloatTypes.Float32)
+ throw new Error('pointComponentType mismatch')
+ if (mesh.meshType.cellComponentType !== itk.IntTypes.UInt32)
+ throw new Error('cellComponentType mismatch')
+ if (mesh.meshType.pointPixelType !== itk.PixelTypes.Scalar)
+ throw new Error('pointPixelType mismatch')
+ if (mesh.meshType.cellPixelType !== itk.PixelTypes.Scalar)
+ throw new Error('cellPixelType mismatch')
+ if (mesh.numberOfPoints !== 2903)
+ throw new Error('numberOfPoints mismatch')
+ if (mesh.numberOfCells !== 3263)
+ throw new Error('numberOfCells mismatch')
+ }
+
+ const readIwm = async (baseUrl) => {
+ const meshResponse = await fetch(`${baseUrl}index.json`)
+ const mesh = await meshResponse.json()
+ const pointsResponse = await fetch(`${baseUrl}data/points.raw`)
+ const pointsBuffer = await pointsResponse.arrayBuffer()
+ const points = new Float32Array(pointsBuffer)
+ mesh.points = points
+ const cellsResponse = await fetch(`${baseUrl}data/cells.raw`)
+ const cellsBuffer = await cellsResponse.arrayBuffer()
+ const cells = new Float32Array(cellsBuffer)
+ mesh.cells = cells
+ // todo
+ mesh.pointData = null
+ mesh.cellData = null
+ return mesh
+ }
+
+ const cowBaseUrl = '/data/cow.iwm/'
+ const mesh = await readIwm(cowBaseUrl)
+
+ const pipelinePath = 'mesh-read-write-test'
+ const args = ['0', '0', '--memory-io']
+ const desiredOutputs = [{ type: itk.InterfaceTypes.Mesh }]
+ const inputs = [{ type: itk.InterfaceTypes.Mesh, data: mesh }]
+ const { webWorker, outputs } = await itk.runPipeline(
+ pipelinePath,
+ args,
+ desiredOutputs,
+ inputs
+ )
+ webWorker.terminate()
+ verifyMesh(outputs[0].data)
+ })
+ })
+})
diff --git a/packages/core/typescript/itk-wasm/test/browser/web-worker-pool.spec.js b/packages/core/typescript/itk-wasm/test/browser/web-worker-pool.spec.js
new file mode 100644
index 000000000..be0d7cdf2
--- /dev/null
+++ b/packages/core/typescript/itk-wasm/test/browser/web-worker-pool.spec.js
@@ -0,0 +1,84 @@
+import { test, expect } from '@playwright/test'
+import { readIwi, pipelineBaseUrl, pipelineWorkerUrl } from './common.js'
+import compareImageToBaseline from './compare-image-to-baseline.js'
+
+test.describe('WebWorkerPool', () => {
+ test('runs and reports progress', async ({ page }) => {
+ await page.goto('/')
+
+ const result = await page.evaluate(
+ async ({ pipelineWorkerUrl, pipelineBaseUrl, readIwi }) => {
+ const itk = window.itk
+ itk.setPipelineWorkerUrl(pipelineWorkerUrl)
+ itk.setPipelinesBaseUrl(pipelineBaseUrl)
+
+ const progressUpdates = []
+ let reportedTotalSplits = null
+ function progressLogger(split, totalSplits) {
+ progressUpdates.push(split)
+ reportedTotalSplits = totalSplits
+ }
+
+ const poolSize = 2
+ const maxTotalSplits = 4
+ const workerPool = new itk.WorkerPool(poolSize, itk.runPipeline)
+
+ // Use the readIwi function passed from Node.js context
+ const readIwiInBrowser = new Function('return ' + readIwi)()
+
+ const cthead1BaseUrl = '/data/cthead1.iwi/'
+ const image = await readIwiInBrowser(cthead1BaseUrl)
+
+ const taskArgsArray = []
+ for (let index = 0; index < maxTotalSplits; index++) {
+ const pipelinePath = 'median-filter-test'
+ const args = [
+ '--memory-io',
+ '0',
+ '0',
+ '--radius',
+ '4',
+ '-m',
+ '' + maxTotalSplits,
+ '-s',
+ '' + index
+ ]
+ const desiredOutputs = [{ type: itk.InterfaceTypes.Image }]
+ const data = itk.imageSharedBufferOrCopy(image)
+ const inputs = [{ type: itk.InterfaceTypes.Image, data }]
+ taskArgsArray.push([pipelinePath, args, desiredOutputs, inputs, {}])
+ }
+
+ const results = await workerPool.runTasks(taskArgsArray, progressLogger)
+ .promise
+ workerPool.terminateWorkers()
+
+ const imageSplits = results.map(({ outputs }) => outputs[0].data)
+ const stackedImage = itk.stackImages(imageSplits)
+
+ const baselineBaseUrl = '/data/web-worker-pool-baseline.iwi/'
+ const baselineImage = await readIwiInBrowser(baselineBaseUrl)
+
+ return {
+ reportedTotalSplits,
+ maxTotalSplits,
+ stackedImage: JSON.parse(JSON.stringify(stackedImage)),
+ baselineImage: JSON.parse(JSON.stringify(baselineImage))
+ }
+ },
+ {
+ pipelineWorkerUrl,
+ pipelineBaseUrl,
+ readIwi: readIwi.toString() // Pass function as string to be reconstructed in browser
+ }
+ )
+
+ expect(result.reportedTotalSplits).toBe(result.maxTotalSplits)
+
+ // Reconstruct the images for comparison
+ const stackedImage = result.stackedImage
+ const baselineImage = result.baselineImage
+
+ compareImageToBaseline(stackedImage, baselineImage)
+ })
+})
diff --git a/packages/core/typescript/itk-wasm/test/pipelines/typescript/package.json b/packages/core/typescript/itk-wasm/test/pipelines/typescript/package.json
index 3ab5f2e81..fb8a2f885 100644
--- a/packages/core/typescript/itk-wasm/test/pipelines/typescript/package.json
+++ b/packages/core/typescript/itk-wasm/test/pipelines/typescript/package.json
@@ -48,4 +48,4 @@
"vite-plugin-cross-origin-isolation": "^0.1.6",
"vite-plugin-static-copy": "^0.17.0"
}
-}
+}
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 33cb2d25b..5bed166a2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -6,7 +6,7 @@ settings:
overrides:
'@shoelace-style/shoelace': ^2.12.0
- '@types/node': ^22.13.13
+ '@types/node': ^24.0.3
esbuild: ^0.25.1
start-server-and-test: ^2.0.12
ava: ^6.1.3
@@ -24,10 +24,13 @@ importers:
version: 2.27.1
'@commitlint/cli':
specifier: ^19.3.0
- version: 19.3.0(@types/node@22.15.21)(typescript@5.8.3)
+ version: 19.3.0(@types/node@24.0.3)(typescript@5.8.3)
'@commitlint/config-conventional':
specifier: ^19.2.2
version: 19.2.2
+ '@playwright/test':
+ specifier: ^1.53.0
+ version: 1.53.1
examples/debugging:
dependencies:
@@ -91,8 +94,8 @@ importers:
specifier: workspace:^
version: link:../../../packages/mesh-io/typescript
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
esbuild:
specifier: ^0.25.1
version: 0.25.2
@@ -104,10 +107,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^0.17.0
- version: 0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
examples/mean-squares-versor-registration:
devDependencies:
@@ -137,8 +140,8 @@ importers:
specifier: workspace:^
version: link:../../../packages/mesh-io/typescript
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
esbuild:
specifier: ^0.25.1
version: 0.25.2
@@ -150,10 +153,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^0.17.0
- version: 0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
examples/node-js:
dependencies:
@@ -198,8 +201,8 @@ importers:
specifier: workspace:^
version: link:../../image-io/typescript
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
ava:
specifier: ^6.1.3
version: 6.1.3
@@ -220,10 +223,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^1.0.0
- version: 1.0.6(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 1.0.6(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
packages/compare-meshes:
devDependencies:
@@ -253,8 +256,8 @@ importers:
specifier: workspace:*
version: link:../../mesh-io/typescript
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
esbuild:
specifier: ^0.25.1
version: 0.25.2
@@ -266,10 +269,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^0.17.0
- version: 0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
packages/compress-stringify:
devDependencies:
@@ -317,8 +320,8 @@ importers:
specifier: ^1.1.0
version: 1.1.0
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
ava:
specifier: ^6.1.3
version: 6.1.3
@@ -339,10 +342,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^0.17.0
- version: 0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
packages/core/typescript/create-itk-wasm:
dependencies:
@@ -378,8 +381,8 @@ importers:
specifier: ^9.0.7
version: 9.0.7
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
'@types/validate-npm-package-name':
specifier: ^4.0.2
version: 4.0.2
@@ -466,15 +469,15 @@ importers:
specifier: ^1.6.1
version: 1.6.1
devDependencies:
+ '@playwright/test':
+ specifier: ^1.53.0
+ version: 1.53.1
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
ava:
specifier: ^6.1.3
version: 6.1.3
- cypress:
- specifier: ^14.5.0
- version: 14.5.0
esbuild:
specifier: ^0.25.1
version: 0.25.2
@@ -490,9 +493,6 @@ importers:
standard:
specifier: ^17.1.0
version: 17.1.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.8.3))
- start-server-and-test:
- specifier: ^2.0.12
- version: 2.0.12
ts-standard:
specifier: ^12.0.2
version: 12.0.2(typescript@5.8.3)
@@ -519,8 +519,8 @@ importers:
specifier: workspace:*
version: link:../../../../../../transform-io/typescript
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
esbuild:
specifier: ^0.25.1
version: 0.25.2
@@ -532,13 +532,13 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-cross-origin-isolation:
specifier: ^0.1.6
version: 0.1.6
vite-plugin-static-copy:
specifier: ^0.17.0
- version: 0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
packages/dicom:
devDependencies:
@@ -574,8 +574,8 @@ importers:
specifier: workspace:*
version: link:../../image-io/typescript
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
ava:
specifier: ^6.1.3
version: 6.1.3
@@ -602,10 +602,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^0.17.0
- version: 0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
packages/downsample:
devDependencies:
@@ -644,8 +644,8 @@ importers:
specifier: workspace:^
version: link:../../mesh-io/typescript
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
ava:
specifier: ^6.1.3
version: 6.1.3
@@ -666,10 +666,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^0.17.0
- version: 0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
packages/image-io:
devDependencies:
@@ -702,8 +702,8 @@ importers:
specifier: ^2.1.4
version: 2.1.4
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
ava:
specifier: ^6.1.3
version: 6.1.3
@@ -727,10 +727,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^1.0.0
- version: 1.0.6(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 1.0.6(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
packages/mesh-filters:
devDependencies:
@@ -766,8 +766,8 @@ importers:
specifier: workspace:*
version: link:../../mesh-io/typescript
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
ava:
specifier: ^6.1.3
version: 6.1.3
@@ -782,10 +782,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^0.17.0
- version: 0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
packages/mesh-io:
devDependencies:
@@ -818,8 +818,8 @@ importers:
specifier: ^2.1.4
version: 2.1.4
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
ava:
specifier: ^6.1.3
version: 6.1.3
@@ -840,10 +840,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^0.17.0
- version: 0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
packages/transform-io:
devDependencies:
@@ -873,8 +873,8 @@ importers:
specifier: ^2.1.4
version: 2.1.4
'@types/node':
- specifier: ^22.13.13
- version: 22.14.0
+ specifier: ^24.0.3
+ version: 24.0.3
ava:
specifier: ^6.1.3
version: 6.1.3
@@ -895,10 +895,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.2.3
- version: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ version: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
vite-plugin-static-copy:
specifier: ^0.17.0
- version: 0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2))
+ version: 0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2))
packages:
@@ -2050,6 +2050,11 @@ packages:
'@perma/map@1.0.3':
resolution: {integrity: sha512-Bf5njk0fnJGTFE2ETntq0N1oJ6YdCPIpTDn3R3KYZJQdeYSOCNL7mBrFlGnbqav8YQhJA/p81pvHINX9vAtHkQ==}
+ '@playwright/test@1.53.1':
+ resolution: {integrity: sha512-Z4c23LHV0muZ8hfv4jw6HngPJkbbtZxTkxPNIg7cJcTc9C28N/p2q7g3JZS2SiKBBHJ3uM1dgDye66bB7LEk5w==}
+ engines: {node: '>=18'}
+ hasBin: true
+
'@protobufjs/aspromise@1.1.2':
resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==}
@@ -2257,11 +2262,8 @@ packages:
'@types/node-fetch@2.6.11':
resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==}
- '@types/node@22.14.0':
- resolution: {integrity: sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==}
-
- '@types/node@22.15.21':
- resolution: {integrity: sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==}
+ '@types/node@24.0.3':
+ resolution: {integrity: sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==}
'@types/normalize-package-data@2.4.4':
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
@@ -3027,7 +3029,7 @@ packages:
resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==}
engines: {node: '>=v16'}
peerDependencies:
- '@types/node': ^22.13.13
+ '@types/node': ^24.0.3
cosmiconfig: '>=8.2'
typescript: ^5.8.3
@@ -3752,6 +3754,11 @@ packages:
fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+ fsevents@2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -5022,6 +5029,16 @@ packages:
resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
engines: {node: '>=8'}
+ playwright-core@1.53.1:
+ resolution: {integrity: sha512-Z46Oq7tLAyT0lGoFx4DOuB1IA9D1TPj0QkYxpPVUnGDqHHvDpCftu1J2hM2PiWsNMoZh8+LQaarAWcDfPBc6zg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ playwright@1.53.1:
+ resolution: {integrity: sha512-LJ13YLr/ocweuwxyGf1XNFWIU4M2zUSo149Qbp+A4cpwDjsxRPj7k6H25LBrEHiEwxvRbD8HdwvQmRMSvquhYw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
plur@5.1.0:
resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -5812,8 +5829,8 @@ packages:
unbzip2-stream@1.4.3:
resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==}
- undici-types@6.21.0:
- resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+ undici-types@7.8.0:
+ resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==}
undici@5.28.4:
resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==}
@@ -5925,7 +5942,7 @@ packages:
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
peerDependencies:
- '@types/node': ^22.13.13
+ '@types/node': ^24.0.3
jiti: '>=1.21.0'
less: '*'
lightningcss: ^1.21.0
@@ -7183,11 +7200,11 @@ snapshots:
dependencies:
commander: 12.0.0
- '@commitlint/cli@19.3.0(@types/node@22.15.21)(typescript@5.8.3)':
+ '@commitlint/cli@19.3.0(@types/node@24.0.3)(typescript@5.8.3)':
dependencies:
'@commitlint/format': 19.3.0
'@commitlint/lint': 19.2.2
- '@commitlint/load': 19.2.0(@types/node@22.15.21)(typescript@5.8.3)
+ '@commitlint/load': 19.2.0(@types/node@24.0.3)(typescript@5.8.3)
'@commitlint/read': 19.2.1
'@commitlint/types': 19.0.3
execa: 8.0.1
@@ -7234,7 +7251,7 @@ snapshots:
'@commitlint/rules': 19.0.3
'@commitlint/types': 19.0.3
- '@commitlint/load@19.2.0(@types/node@22.15.21)(typescript@5.8.3)':
+ '@commitlint/load@19.2.0(@types/node@24.0.3)(typescript@5.8.3)':
dependencies:
'@commitlint/config-validator': 19.0.3
'@commitlint/execute-rule': 19.0.0
@@ -7242,7 +7259,7 @@ snapshots:
'@commitlint/types': 19.0.3
chalk: 5.3.0
cosmiconfig: 9.0.0(typescript@5.8.3)
- cosmiconfig-typescript-loader: 5.0.0(@types/node@22.15.21)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3)
+ cosmiconfig-typescript-loader: 5.0.0(@types/node@24.0.3)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3)
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
lodash.uniq: 4.5.0
@@ -7687,7 +7704,7 @@ snapshots:
'@manypkg/find-root@1.1.0':
dependencies:
'@babel/runtime': 7.24.5
- '@types/node': 22.14.0
+ '@types/node': 24.0.3
find-up: 4.1.0
fs-extra: 8.1.0
@@ -7773,6 +7790,10 @@ snapshots:
'@multiformats/murmur3': 2.1.8
murmurhash3js-revisited: 3.0.0
+ '@playwright/test@1.53.1':
+ dependencies:
+ playwright: 1.53.1
+
'@protobufjs/aspromise@1.1.2': {}
'@protobufjs/base64@1.1.2': {}
@@ -7911,7 +7932,7 @@ snapshots:
'@types/conventional-commits-parser@5.0.0':
dependencies:
- '@types/node': 22.14.0
+ '@types/node': 24.0.3
'@types/emscripten@1.39.11': {}
@@ -7944,16 +7965,12 @@ snapshots:
'@types/node-fetch@2.6.11':
dependencies:
- '@types/node': 22.14.0
+ '@types/node': 24.0.3
form-data: 4.0.2
- '@types/node@22.14.0':
- dependencies:
- undici-types: 6.21.0
-
- '@types/node@22.15.21':
+ '@types/node@24.0.3':
dependencies:
- undici-types: 6.21.0
+ undici-types: 7.8.0
'@types/normalize-package-data@2.4.4': {}
@@ -7972,13 +7989,13 @@ snapshots:
'@types/through@0.0.33':
dependencies:
- '@types/node': 22.14.0
+ '@types/node': 24.0.3
'@types/trusted-types@2.0.7': {}
'@types/tunnel@0.0.3':
dependencies:
- '@types/node': 22.14.0
+ '@types/node': 24.0.3
'@types/validate-npm-package-name@4.0.2': {}
@@ -7986,7 +8003,7 @@ snapshots:
'@types/yauzl@2.10.3':
dependencies:
- '@types/node': 22.15.21
+ '@types/node': 24.0.3
optional: true
'@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0)(typescript@5.8.3)':
@@ -8831,9 +8848,9 @@ snapshots:
corser@2.0.1: {}
- cosmiconfig-typescript-loader@5.0.0(@types/node@22.15.21)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3):
+ cosmiconfig-typescript-loader@5.0.0(@types/node@24.0.3)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3):
dependencies:
- '@types/node': 22.15.21
+ '@types/node': 24.0.3
cosmiconfig: 9.0.0(typescript@5.8.3)
jiti: 1.21.0
typescript: 5.8.3
@@ -9767,6 +9784,9 @@ snapshots:
fs.realpath@1.0.0: {}
+ fsevents@2.3.2:
+ optional: true
+
fsevents@2.3.3:
optional: true
@@ -10398,7 +10418,7 @@ snapshots:
jest-worker@27.5.1:
dependencies:
- '@types/node': 22.15.21
+ '@types/node': 24.0.3
merge-stream: 2.0.0
supports-color: 8.1.1
@@ -11033,6 +11053,14 @@ snapshots:
dependencies:
find-up: 4.1.0
+ playwright-core@1.53.1: {}
+
+ playwright@1.53.1:
+ dependencies:
+ playwright-core: 1.53.1
+ optionalDependencies:
+ fsevents: 2.3.2
+
plur@5.1.0:
dependencies:
irregular-plurals: 3.5.0
@@ -11102,7 +11130,7 @@ snapshots:
'@protobufjs/path': 1.1.2
'@protobufjs/pool': 1.1.0
'@protobufjs/utf8': 1.1.0
- '@types/node': 22.14.0
+ '@types/node': 24.0.3
long: 5.2.3
protons-runtime@5.4.0:
@@ -11949,7 +11977,7 @@ snapshots:
buffer: 5.7.1
through: 2.3.8
- undici-types@6.21.0: {}
+ undici-types@7.8.0: {}
undici@5.28.4:
dependencies:
@@ -12019,29 +12047,29 @@ snapshots:
vite-plugin-cross-origin-isolation@0.1.6: {}
- vite-plugin-static-copy@0.17.1(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)):
+ vite-plugin-static-copy@0.17.1(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)):
dependencies:
chokidar: 3.6.0
fast-glob: 3.3.2
fs-extra: 11.2.0
picocolors: 1.1.1
- vite: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ vite: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
- vite-plugin-static-copy@1.0.6(vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)):
+ vite-plugin-static-copy@1.0.6(vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)):
dependencies:
chokidar: 3.6.0
fast-glob: 3.3.2
fs-extra: 11.2.0
picocolors: 1.1.1
- vite: 6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2)
+ vite: 6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2)
- vite@6.2.7(@types/node@22.14.0)(jiti@1.21.0)(terser@5.39.2):
+ vite@6.2.7(@types/node@24.0.3)(jiti@1.21.0)(terser@5.39.2):
dependencies:
esbuild: 0.25.2
postcss: 8.5.3
rollup: 4.41.0
optionalDependencies:
- '@types/node': 22.14.0
+ '@types/node': 24.0.3
fsevents: 2.3.3
jiti: 1.21.0
terser: 5.39.2
@@ -12221,7 +12249,7 @@ snapshots:
'@oozcitak/dom': 1.15.10
'@oozcitak/infra': 1.0.8
'@oozcitak/util': 8.3.8
- '@types/node': 22.14.0
+ '@types/node': 24.0.3
js-yaml: 3.14.0
xmlbuilder@11.0.1: {}