Skip to content
Draft
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
36 changes: 25 additions & 11 deletions packages/typegpu-confetti/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"sideEffects": false,
"scripts": {
"build": "tsx prepack.mjs",
"prepublishOnly": "pnpm run build"
"prepublishOnly": "pnpm run build",
"test": "vitest"
},
"engines": {
"node": ">=12.20.0"
Expand All @@ -51,30 +52,43 @@
"type": "git",
"url": "git+https://github.com/mhawryluk/typegpu-confetti.git"
},
"keywords": ["confetti", "javascript", "react-native", "webgpu", "react"],
"keywords": [
"confetti",
"javascript",
"react-native",
"webgpu",
"react"
],
"bugs": {
"url": "https://github.com/mhawryluk/typegpu-confetti/issues"
},
"dependencies": {
"typegpu": "^0.6.0",
"@typegpu/noise": "^0.1.0"
"@typegpu/noise": "^0.1.0",
"typegpu": "^0.6.0"
},
"peerDependencies": {
"react": "*",
"react-native": "*",
"react-native-wgpu": "*"
},
"devDependencies": {
"typescript": "^5.7.3",
"@testing-library/jest-dom": "^6.6.4",
"@testing-library/react": "^16.3.0",
"@types/testing-library__jest-dom": "^6.0.0",
"@types/testing-library__react": "^10.2.0",
"@webgpu/types": "^0.1.54",
"unbuild": "^3.5.0",
"unplugin-typegpu": "^0.2.1",
"react-native-wgpu": "^0.1.23",
"react-native": "^0.79.3",
"react": "^19.1.0",
"execa": "^9.6.0",
"jsdom": "^26.1.0",
"react": "^19.1.0",
"react-native": "^0.79.3",
"react-native-wgpu": "^0.1.23",
"remeda": "^2.21.2",
"tsx": "^4.19.4"
"tsx": "^4.19.4",
"typescript": "^5.7.3",
"unbuild": "^3.5.0",
"unplugin-typegpu": "^0.2.1",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^3.2.4"
},
"packageManager": "[email protected]+sha512.60c18acd138bff695d339be6ad13f7e936eea6745660d4cc4a776d5247c540d0edee1a563695c183a66eb917ef88f2b4feb1fc25f32a7adcadc7aaf3438e99c1"
}
17 changes: 17 additions & 0 deletions packages/typegpu-confetti/src/__test__/context.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { RootContext } from '../context';

describe('RootContext', () => {
it('should be a React context with null as default value', () => {
expect(RootContext).toBeDefined();
expect(RootContext.displayName).toBeUndefined();

expect(RootContext.Provider).toBeDefined();
expect(RootContext.Consumer).toBeDefined();
});

it('should have the correct context structure', () => {
expect(typeof RootContext).toBe('object');
expect('Provider' in RootContext).toBe(true);
expect('Consumer' in RootContext).toBe(true);
});
});
51 changes: 51 additions & 0 deletions packages/typegpu-confetti/src/__test__/defaults.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { defaults } from '../defaults';

describe('defaults', () => {
it('should have correct default values', () => {
expect(defaults.maxDurationTime).toBe(2);
expect(defaults.initParticleAmount).toBe(200);
expect(defaults.maxParticleAmount).toBe(1000);
expect(defaults.size).toBe(1);
});

it('should have default color palette with correct structure', () => {
expect(Array.isArray(defaults.colorPalette)).toBe(true);
expect(defaults.colorPalette).toHaveLength(5);

// Check each color is an array of 4 numbers (RGBA)
for (const color of defaults.colorPalette) {
expect(Array.isArray(color)).toBe(true);
expect(color).toHaveLength(4);
for (const component of color) {
expect(typeof component).toBe('number');
// RGB values should be 0-255, alpha should be 0-1
expect(component).toBeGreaterThanOrEqual(0);
}
}
});

it('should have gravity function', () => {
expect(typeof defaults.gravity).toBe('function');
});

it('should have initParticle function', () => {
expect(typeof defaults.initParticle).toBe('function');
});

it('should contain all required properties from ConfettiPropTypes', () => {
const expectedKeys = [
'maxDurationTime',
'initParticleAmount',
'maxParticleAmount',
'size',
'colorPalette',
'gravity',
'initParticle'
];

for (const key of expectedKeys) {
expect(defaults).toHaveProperty(key);
expect(defaults[key as keyof typeof defaults]).toBeDefined();
}
});
});
51 changes: 51 additions & 0 deletions packages/typegpu-confetti/src/__test__/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as MainIndex from '../index';

describe('Main index exports', () => {
it('should export schema-related items', () => {
const schemaExports = [
'canvasAspectRatio',
'particles',
'maxDurationTime',
'initParticle',
'maxParticleAmount',
'deltaTime',
'time',
'gravity',
'gravityFn',
'initParticleFn'
];

for (const exportName of schemaExports) {
expect(MainIndex).toHaveProperty(exportName);
expect(MainIndex[exportName as keyof typeof MainIndex]).toBeDefined();
}
});

it('should export function shells', () => {
expect(MainIndex.gravityFn).toBeDefined();
expect(MainIndex.initParticleFn).toBeDefined();
expect(typeof MainIndex.gravityFn).toBe('function');
expect(typeof MainIndex.initParticleFn).toBe('function');
});

it('should export all expected schema items', () => {
const expectedExports = [
'canvasAspectRatio',
'particles',
'maxDurationTime',
'initParticle',
'maxParticleAmount',
'deltaTime',
'time',
'gravity',
'gravityFn',
'initParticleFn'
];

const actualExports = Object.keys(MainIndex);

for (const expectedExport of expectedExports) {
expect(actualExports).toContain(expectedExport);
}
});
});
77 changes: 77 additions & 0 deletions packages/typegpu-confetti/src/__test__/schemas.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import * as d from 'typegpu/data';
import {
VertexOutput,
ParticleGeometry,
ParticleData,
canvasAspectRatio,
particles,
maxDurationTime,
initParticle,
maxParticleAmount,
deltaTime,
time,
gravity,
gravityFn,
initParticleFn,
rotate,
} from '../schemas';

describe('schemas', () => {
describe('data structures', () => {
it('should define VertexOutput correctly', () => {
expect(VertexOutput).toBeDefined();
expect(VertexOutput.position).toBe(d.builtin.position);
expect(VertexOutput.color).toBe(d.vec4f);
expect(VertexOutput.isExpired).toBeDefined();
});

it('should define ParticleGeometry struct', () => {
expect(ParticleGeometry).toBeDefined();
expect(typeof ParticleGeometry).toBe('function');
});

it('should define ParticleData struct', () => {
expect(ParticleData).toBeDefined();
expect(typeof ParticleData).toBe('function');
});
});

describe('slots and accessors', () => {
it('should define canvasAspectRatio accessor', () => {
expect(canvasAspectRatio).toBeDefined();
});

it('should define particles accessor', () => {
expect(particles).toBeDefined();
});

it('should define slots', () => {
expect(maxDurationTime).toBeDefined();
expect(initParticle).toBeDefined();
expect(maxParticleAmount).toBeDefined();
expect(gravity).toBeDefined();
});

it('should define time-related accessors', () => {
expect(deltaTime).toBeDefined();
expect(time).toBeDefined();
});
});

describe('functions', () => {
it('should define gravityFn', () => {
expect(gravityFn).toBeDefined();
expect(typeof gravityFn).toBe('function');
});

it('should define initParticleFn', () => {
expect(initParticleFn).toBeDefined();
expect(typeof initParticleFn).toBe('function');
});

it('should define rotate function', () => {
expect(rotate).toBeDefined();
expect(typeof rotate).toBe('function');
});
});
});
77 changes: 77 additions & 0 deletions packages/typegpu-confetti/src/__test__/types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { ConfettiPropTypes, ConfettiRef } from '../types';

describe('types', () => {
describe('ConfettiPropTypes', () => {
it('should allow optional colorPalette property', () => {
const validProps: ConfettiPropTypes = {
colorPalette: [[255, 0, 0, 1], [0, 255, 0, 1]]
};
expect(validProps.colorPalette).toBeDefined();
});

it('should allow optional size property', () => {
const validProps: ConfettiPropTypes = {
size: 2
};
expect(validProps.size).toBe(2);
});

it('should allow optional maxDurationTime property', () => {
const validProps: ConfettiPropTypes = {
maxDurationTime: 5
};
expect(validProps.maxDurationTime).toBe(5);
});

it('should allow maxDurationTime to be null', () => {
const validProps: ConfettiPropTypes = {
maxDurationTime: null
};
expect(validProps.maxDurationTime).toBeNull();
});

it('should allow optional particle amount properties', () => {
const validProps: ConfettiPropTypes = {
initParticleAmount: 100,
maxParticleAmount: 500
};
expect(validProps.initParticleAmount).toBe(100);
expect(validProps.maxParticleAmount).toBe(500);
});

it('should allow empty object as valid ConfettiPropTypes', () => {
const validProps: ConfettiPropTypes = {};
expect(typeof validProps).toBe('object');
});
});

describe('ConfettiRef', () => {
it('should define required methods', () => {
// This is a type test - if it compiles, the type is correctly defined
const mockRef: ConfettiRef = {
pause: () => {},
resume: () => {},
restart: () => {},
addParticles: (amount: number) => {}
};

expect(typeof mockRef.pause).toBe('function');
expect(typeof mockRef.resume).toBe('function');
expect(typeof mockRef.restart).toBe('function');
expect(typeof mockRef.addParticles).toBe('function');
});

it('should have addParticles method that accepts number parameter', () => {
const mockRef: ConfettiRef = {
pause: () => {},
resume: () => {},
restart: () => {},
addParticles: (amount: number) => {
expect(typeof amount).toBe('number');
}
};

mockRef.addParticles(10);
});
});
});
Loading