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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ jobs:

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Test
run: pnpm test

- name: Build docs

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs are now built as part of the test script

Comment thread
iwoplaza marked this conversation as resolved.
run: cd apps/typegpu-docs && pnpm build
4 changes: 4 additions & 0 deletions apps/typegpu-docs/vitest.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import type TypeGPUPlugin from 'unplugin-typegpu/vite';
import { imagetools } from 'vite-imagetools';
import { defineConfig, type Plugin } from 'vitest/config';
import { preview } from '@vitest/browser-preview';
import { typegpuBuiltAliases } from 'typegpu-testing-utility/config';

const jiti = createJiti(import.meta.url);
const typegpu = await jiti.import<typeof TypeGPUPlugin>('unplugin-typegpu/vite', { default: true });

export default defineConfig({
plugins: [typegpu({ include: [/\.m?[jt]sx?/] }), imagetools()] as Plugin[],
resolve: {
alias: typegpuBuiltAliases(),
},
server: {
proxy: {
'/TypeGPU': {
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
"dev": "DEV=true pnpm run --filter typegpu-docs dev",
"dev:host": "DEV=true pnpm run --filter typegpu-docs dev --host --mode https",
"fix": "oxlint -c oxlint.config.ts --fix && oxfmt",
"test": "pnpm run test:types && pnpm run test:style && pnpm run test:unit-and-attest && pnpm run test:circular-deps",
"test": "pnpm run test:types && pnpm run test:style && pnpm run test:unit-and-attest && pnpm run test:built-unit-and-attest && pnpm run test:circular-deps",
"test:circular-deps": "pnpm dpdm -T --exit-code circular:1 packages/**/src/index.ts packages/**/src/index.js !packages/**/node_modules",
"test:types": "pnpm run --filter typegpu-docs transform-overloads && pnpm run -r --parallel test:types",
"test:style": "oxlint -c oxlint.config.ts --max-warnings=0 --type-aware --ignore-pattern 'packages/typegpu-cli/templates/template-expo-bare/**' --report-unused-disable-directives && oxlint -c oxlint.config.ts --max-warnings=0 packages/typegpu-cli/templates/template-expo-bare --report-unused-disable-directives && oxfmt --check",
"test:unit-and-attest": "ENABLE_ATTEST=1 vitest run --project=!browser",
"test:unit": "vitest run --project=!browser",
"test:built-unit": "pnpm run --filter './packages/*' build && TEST_BUILT=1 vitest run --project=!browser",
"test:built-unit-and-attest": "pnpm run --filter './packages/*' build && TEST_BUILT=1 ENABLE_ATTEST=1 vitest run --project=!browser",
"test:unit:watch": "vitest --project=!browser",
"test:browser": "vitest run --browser.enabled --project browser",
"test:browser:watch": "vitest --browser.enabled --project browser",
Expand All @@ -51,6 +53,7 @@
"oxlint": "^1.57.0",
"oxlint-tsgolint": "^0.17.4",
"pkg-pr-new": "^0.0.66",
"typegpu-testing-utility": "workspace:*",
"typescript": "catalog:types",
"unplugin-typegpu": "workspace:*",
"vite-imagetools": "catalog:frontend",
Expand Down
4 changes: 4 additions & 0 deletions packages/typegpu-gl/vitest.config.mts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { createJiti } from 'jiti';
import type TypeGPUPlugin from 'unplugin-typegpu/vite';
import { defineConfig } from 'vitest/config';
import { typegpuBuiltAliases } from 'typegpu-testing-utility/config';

const jiti = createJiti(import.meta.url);
const typegpu = await jiti.import<typeof TypeGPUPlugin>('unplugin-typegpu/vite', { default: true });

export default defineConfig({
plugins: [typegpu({ forceTgpuAlias: 'tgpu', earlyPruning: false })],
resolve: {
alias: typegpuBuiltAliases(),
},
});
14 changes: 4 additions & 10 deletions packages/typegpu-react/tests/root-context.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { act, render } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, vi } from 'vitest';
import tgpu from 'typegpu';
import type { TgpuRoot } from 'typegpu';
import { Root, useRootWithStatus } from '@typegpu/react';
import { useEffect } from 'react';
Expand Down Expand Up @@ -56,15 +55,9 @@ describe('Root unmount cleanup', () => {
});

it('should destroy root when init promise resolves after unmount', async ({
root: fixtureRoot,
stallDeviceRequest,
}) => {
let resolveInit!: (root: TgpuRoot) => void;
const initPromise = new Promise<TgpuRoot>((resolve) => {
resolveInit = resolve;
});

using _initSpy = vi.spyOn(tgpu, 'init').mockReturnValue(initPromise);
const destroySpy = vi.spyOn(fixtureRoot, 'destroy');
const resume = stallDeviceRequest();

function TestConsumer() {
useRootWithStatus();
Expand All @@ -82,7 +75,8 @@ describe('Root unmount cleanup', () => {
vi.runAllTimers();

// Resolve init after context has been destroyed
resolveInit(fixtureRoot);
const device = await resume();
const destroySpy = vi.spyOn(device, 'destroy');

Comment thread
iwoplaza marked this conversation as resolved.
// Flush microtasks so the .then() callback runs
await act(async () => {
Expand Down
4 changes: 4 additions & 0 deletions packages/typegpu-react/vitest.config.mts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { createJiti } from 'jiti';
import type TypeGPUPlugin from 'unplugin-typegpu/vite';
import { defineConfig } from 'vitest/config';
import { typegpuBuiltAliases } from 'typegpu-testing-utility/config';

const jiti = createJiti(import.meta.url);
const typegpu = await jiti.import<typeof TypeGPUPlugin>('unplugin-typegpu/vite', { default: true });

export default defineConfig({
plugins: [typegpu({ forceTgpuAlias: 'tgpu', earlyPruning: false })],
resolve: {
alias: typegpuBuiltAliases(),
},
esbuild: {
jsx: 'automatic',
jsxImportSource: 'react',
Expand Down
5 changes: 4 additions & 1 deletion packages/typegpu-testing-utility/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
"private": true,
"license": "MIT",
"type": "module",
"exports": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./config": "./src/config.ts"
},
"scripts": {
"test:types": "pnpm tsc --p ./tsconfig.json --noEmit"
},
Expand Down
25 changes: 25 additions & 0 deletions packages/typegpu-testing-utility/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
type Alias = {
find: RegExp;
replacement: string;
};

export function isTestingBuiltTypegpu() {
return process.env.TEST_BUILT === '1' || process.env.TEST_BUILT === 'true';
}

export function typegpuBuiltAliases(): Alias[] {
if (!isTestingBuiltTypegpu()) {
return [];
}

return [
{
find: /^typegpu$/,
replacement: 'typegpu/$built$',
},
{
find: /^typegpu\/(?!package\.json$)(?!.*\/\$built\$$)(.+)$/,
replacement: 'typegpu/$1/$built$',
},
];
Comment thread
iwoplaza marked this conversation as resolved.
}
60 changes: 58 additions & 2 deletions packages/typegpu-testing-utility/src/extendedIt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,39 @@ export const it = base

return mockDevice as unknown as GPUDevice & { mock: typeof mockDevice };
})
.extend('adapter', ({ device }) => {
.extend('_stallDeviceRequest', ({ device }) => {
let stallResolve: () => void;
let stallPromise: Promise<void> | undefined;
let devicePromise: Promise<GPUDevice> | undefined;

const result = {
enabled: false,
get stallPromise() {
return (stallPromise ??= new Promise<void>((r) => {
stallResolve = r;
}));
},
get devicePromise(): Promise<GPUDevice> {
return (devicePromise ??= this.stallPromise.then(() => device));
},
get stallResolve() {
void this.stallPromise; // ensuring the promise is initialized
return stallResolve;
},
};
Comment thread
iwoplaza marked this conversation as resolved.

return result;
})
.extend('adapter', ({ device, _stallDeviceRequest }) => {
const adapterMock = {
features: new Set(['timestamp-query']),
requestDevice: vi.fn((_descriptor) => Promise.resolve(device)),
requestDevice: vi.fn((_descriptor) => {
if (_stallDeviceRequest.enabled) {
return _stallDeviceRequest.devicePromise;
}

return Promise.resolve(device);
}),
limits: {
maxStorageBufferBindingSize: 64 * 1024 * 1024,
maxBufferSize: 64 * 1024 * 1024,
Expand Down Expand Up @@ -171,6 +200,33 @@ export const it = base
vi.unstubAllGlobals();
});
})
/**
* Used to introduce an artificial delay between requesting a device and getting it.
* @example
* ```ts
* it('foo', async ({ stallDeviceRequest }) => {
* const resume = stallDeviceRequest();
*
* // do something asynchronous that requests a device
*
* const device = await resume(); // causes the device to resolve
* });
* ```
*/
.extend('stallDeviceRequest', ({ _stallDeviceRequest }) => {
return () => {
if (_stallDeviceRequest.enabled) {
throw new Error('Cannot stall .requestDevice() more than once at a time');
}
_stallDeviceRequest.enabled = true;

return async () => {
_stallDeviceRequest.stallResolve();
_stallDeviceRequest.enabled = false;
return await _stallDeviceRequest.devicePromise;
};
};
})
.extend('root', async ({}, { onCleanup }) => {
const root = await tgpu.init();

Expand Down
9 changes: 6 additions & 3 deletions packages/typegpu/setupVitest.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { setup } from '@ark/attest';
import { type } from 'arktype';

const truthyString = type('"0"|"1"').pipe.try((value) => Boolean(Number.parseInt(value)));
const truthyString = type('"0"|"1"|"true"|"false"').pipe.try(
(value) => value === '1' || value === 'true',
);

const ProcessEnvType = type({
'ENABLE_ATTEST?': type.or(truthyString, 'undefined'),
});

const env = ProcessEnvType.assert(process.env);

export default () =>
setup({
export default () => {
return setup({
formatCmd: 'pnpm fix',
// Skipping type tests by default
skipTypes: !env.ENABLE_ATTEST,
});
};
10 changes: 9 additions & 1 deletion packages/typegpu/vitest.config.mts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import { createJiti } from 'jiti';
import type TypeGPUPlugin from 'unplugin-typegpu/vite';
import { defineConfig } from 'vitest/config';
import { configDefaults, defineConfig } from 'vitest/config';
import { isTestingBuiltTypegpu, typegpuBuiltAliases } from 'typegpu-testing-utility/config';

const jiti = createJiti(import.meta.url);
const typegpu = await jiti.import<typeof TypeGPUPlugin>('unplugin-typegpu/vite', { default: true });
const testBuilt = isTestingBuiltTypegpu();

export default defineConfig({
plugins: [typegpu({ forceTgpuAlias: 'tgpu', earlyPruning: false })],
resolve: {
alias: typegpuBuiltAliases(),
},
test: {
exclude: testBuilt
? [...configDefaults.exclude, 'tests/internal/**/*.{test,spec}.?(c|m)[jt]s?(x)']
: configDefaults.exclude,
globalSetup: ['setupVitest.ts'],
},
});
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions vitest.config.mts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { defineConfig } from 'vitest/config';
import { typegpuBuiltAliases } from 'typegpu-testing-utility/config';

export default defineConfig({
resolve: {
alias: typegpuBuiltAliases(),
},
test: {
projects: ['packages/*', 'apps/*'],
},
Expand Down
Loading