From e3f9455caec4c94b43649ae21ccfac80e6d3e4ed Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Mon, 6 Oct 2025 15:00:40 -0700 Subject: [PATCH] test: vitest tests for puter js (#1693) --- package-lock.json | 79 ++++++++++++++++++++++++++-- package.json | 5 +- src/puter-js/index.d.ts | 4 +- src/puter-js/src/modules/KV.js | 4 +- tests/integration/package.json | 20 +++++++ tests/puterJsApiTests/kv.test.ts | 61 +++++++++++++++++++++ tests/puterJsApiTests/setup.ts | 7 +++ tests/puterJsApiTests/testUtils.ts | 16 ++++++ tests/puterJsApiTests/vite.config.ts | 23 ++++++++ 9 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 tests/integration/package.json create mode 100644 tests/puterJsApiTests/kv.test.ts create mode 100644 tests/puterJsApiTests/setup.ts create mode 100644 tests/puterJsApiTests/testUtils.ts create mode 100644 tests/puterJsApiTests/vite.config.ts diff --git a/package-lock.json b/package-lock.json index fd2fee4c8..81ea7a9e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,8 @@ "mocha": "^10.6.0", "nodemon": "^3.1.0", "uglify-js": "^3.17.4", + "vite-plugin-static-copy": "^3.1.3", + "vitest": "^3.2.4", "webpack": "^5.88.2", "webpack-cli": "^5.1.1" }, @@ -11986,7 +11988,6 @@ "version": "4.0.3", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -12745,6 +12746,7 @@ "node_modules/rollup": { "version": "4.52.4", "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -13959,7 +13961,6 @@ "node_modules/terser": { "version": "5.44.0", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", @@ -14586,8 +14587,81 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/vite-plugin-static-copy": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-3.1.3.tgz", + "integrity": "sha512-U47jgyoJfrvreF87u2udU6dHIXbHhdgGZ7wSEqn6nVHKDOMdRoB2uVc6iqxbEzENN5JvX6djE5cBhQZ2MMBclA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.6.0", + "fs-extra": "^11.3.2", + "p-map": "^7.0.3", + "picocolors": "^1.1.1", + "tinyglobby": "^0.2.15" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/vite-plugin-static-copy/node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/vite-plugin-static-copy/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/vite-plugin-static-copy/node_modules/p-map": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vite-plugin-static-copy/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/vitest": { "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", "dependencies": { @@ -15226,7 +15300,6 @@ "node_modules/yaml": { "version": "2.8.1", "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index e757eebb7..5836b341c 100644 --- a/package.json +++ b/package.json @@ -26,11 +26,14 @@ "mocha": "^10.6.0", "nodemon": "^3.1.0", "uglify-js": "^3.17.4", + "vite-plugin-static-copy": "^3.1.3", + "vitest": "^3.2.4", "webpack": "^5.88.2", "webpack-cli": "^5.1.1" }, "scripts": { "test": "npx mocha src/phoenix/test && npx vitest run src/backend && node src/backend/tools/test", + "test:puterjs-api": "vitest run tests/puterJsApiTests", "start=gui": "nodemon --exec \"node dev-server.js\" ", "start": "node ./tools/run-selfhosted.js", "build": "cd src/gui; node ./build.js", @@ -75,4 +78,4 @@ "engines": { "node": ">=20.19.5" } -} +} \ No newline at end of file diff --git a/src/puter-js/index.d.ts b/src/puter-js/index.d.ts index bcfcd334a..5e81580cb 100644 --- a/src/puter-js/index.d.ts +++ b/src/puter-js/index.d.ts @@ -297,8 +297,8 @@ interface KV { set(key: string, value: string | number | boolean | object | any[]): Promise; get(key: string): Promise; del(key: string): Promise; - incr(key: string, amount?: number): Promise; - decr(key: string, amount?: number): Promise; + incr(key: string, pathAndAmount: { [key: string]: number }): Promise; + decr(key: string, pathAndAmount: { [key: string]: number }): Promise; list(pattern?: string, returnValues?: boolean): Promise; list(returnValues?: boolean): Promise; flush(): Promise; diff --git a/src/puter-js/src/modules/KV.js b/src/puter-js/src/modules/KV.js index f65319a5a..6337c5a97 100644 --- a/src/puter-js/src/modules/KV.js +++ b/src/puter-js/src/modules/KV.js @@ -173,7 +173,7 @@ class KV{ } options.key = args[0]; - options.amount = args[1] ?? 1; + options.pathAndAmountMap = args[1] ?? { '': 1 }; // key size cannot be larger than MAX_KEY_SIZE if ( options.key.length > this.MAX_KEY_SIZE ){ @@ -192,7 +192,7 @@ class KV{ } options.key = args[0]; - options.amount = args[1] ?? 1; + options.pathAndAmountMap = args[1] ?? { '': 1 }; // key size cannot be larger than MAX_KEY_SIZE if ( options.key.length > this.MAX_KEY_SIZE ){ diff --git a/tests/integration/package.json b/tests/integration/package.json new file mode 100644 index 000000000..4c9291133 --- /dev/null +++ b/tests/integration/package.json @@ -0,0 +1,20 @@ +{ + "name": "puter-integration-tests", + "version": "1.0.0", + "description": "Integration tests for Puter", + "main": "index.js", + "scripts": { + "test": "mocha captcha/**/*.test.js", + "test:auth": "mocha captcha/authentication-flow.test.js", + "test:ui": "mocha captcha/ui-behavior.test.js" + }, + "devDependencies": { + "chai": "^4.3.7", + "express": "^4.18.2", + "jsdom": "^21.1.0", + "mocha": "^10.2.0", + "sinon": "^15.2.0", + "body-parser": "^1.20.2", + "supertest": "^6.3.3" + } +} \ No newline at end of file diff --git a/tests/puterJsApiTests/kv.test.ts b/tests/puterJsApiTests/kv.test.ts new file mode 100644 index 000000000..ecf822eb2 --- /dev/null +++ b/tests/puterJsApiTests/kv.test.ts @@ -0,0 +1,61 @@ +// kv.test.ts - Tests for Puter KV module (set, get, del, incr, decr, list, flush) +import { describe, expect, it } from 'vitest'; +import { puter } from './testUtils'; +describe('Puter KV Module', () => { + + const TEST_KEY = 'test-key'; + it('should set a key success', async () => { + await expect(puter.kv.set(TEST_KEY, 0)).resolves.toBe(true); + }); + + it('should get a key success', async () => { + const getRes = await puter.kv.get(TEST_KEY); + expect(getRes).toBe(0); + }); + it('should get empty key', async () => { + const emptyRes = await puter.kv.get('fake' + TEST_KEY) + expect(emptyRes).toBeNull(); + }); + + it('should increment a key success', async () => { + const getRes = await puter.kv.get(TEST_KEY); + expect(getRes).toBe(0); + const incrRes = await puter.kv.incr(TEST_KEY, { '': 5 }); + console.log('incrRes', incrRes); + expect(incrRes).toBe(5); + const finalGet = await puter.kv.get(TEST_KEY); + expect(finalGet).toBe(5); + }); + + it('should decrement a key success', async () => { + const getRes = await puter.kv.get(TEST_KEY); + expect(getRes).toBe(5); + const decrRes = await puter.kv.decr(TEST_KEY, { '': 3 }); + console.log('decrRes', decrRes); + expect(decrRes).toBe(2); + const finalGet = await puter.kv.get(TEST_KEY); + expect(finalGet).toBe(2); + }); + it('should list keys', async () => { + const listRes = await puter.kv.list(); + expect(Array.isArray(listRes)).toBe(true); + expect(listRes.length).toBeGreaterThan(0); + expect((listRes as string[]).includes(TEST_KEY)).toBe(true); + }); + // delete ops should go last + it('should flush all keys', async () => { + const flushRes = await puter.kv.flush() + expect(flushRes).toBe(true); + const postFlushList = await puter.kv.list(); + expect(Array.isArray(postFlushList)).toBe(true); + expect(postFlushList.length).toBe(0); + }); + it('should delete a key success', async () => { + const setRes = await puter.kv.set(TEST_KEY, 'to-be-deleted'); + expect(setRes).toBe(true); + const delRes = await puter.kv.del(TEST_KEY); + expect(delRes).toBe(true); + const getRes = await puter.kv.get(TEST_KEY); + expect(getRes).toBeNull(); + }); +}); \ No newline at end of file diff --git a/tests/puterJsApiTests/setup.ts b/tests/puterJsApiTests/setup.ts new file mode 100644 index 000000000..a2f2e596f --- /dev/null +++ b/tests/puterJsApiTests/setup.ts @@ -0,0 +1,7 @@ +// setup.ts - Vitest global setup for Puter API tests (TypeScript) +import { beforeAll } from 'vitest'; + +beforeAll(async () => { + // Setup global mocks or environment if needed + // Example: globalThis.fetch = ... +}); \ No newline at end of file diff --git a/tests/puterJsApiTests/testUtils.ts b/tests/puterJsApiTests/testUtils.ts new file mode 100644 index 000000000..5bf505ef3 --- /dev/null +++ b/tests/puterJsApiTests/testUtils.ts @@ -0,0 +1,16 @@ +// testUtils.ts - Puter.js API test utilities (TypeScript) +import type { Puter } from '../../src/puter-js'; + +// Create and configure a global puter instance from environment variables +// Usage: import { puter } from './testUtils' +// Environment variables: PUTER_AUTH_TOKEN, PUTER_API_ORIGIN, PUTER_ORIGIN + +// @ts-ignore +const puter: Puter = require('../../src/puter-js/src/index.js').default || globalThis.puter; +globalThis.PUTER_ORIGIN = process.env.PUTER_ORIGIN || 'https://puter.com'; +globalThis.PUTER_API_ORIGIN = process.env.PUTER_API_ORIGIN || 'https://api.puter.com'; +if (process.env.PUTER_API_ORIGIN) (puter as any).setAPIOrigin(process.env.PUTER_API_ORIGIN); +if (process.env.PUTER_ORIGIN) (puter as any).defaultGUIOrigin = process.env.PUTER_ORIGIN; +if (process.env.PUTER_AUTH_TOKEN) (puter as any).setAuthToken(process.env.PUTER_AUTH_TOKEN); + +export { puter }; diff --git a/tests/puterJsApiTests/vite.config.ts b/tests/puterJsApiTests/vite.config.ts new file mode 100644 index 000000000..f5b4a5a6e --- /dev/null +++ b/tests/puterJsApiTests/vite.config.ts @@ -0,0 +1,23 @@ +// vite.config.ts - Vite configuration for Puter API tests (TypeScript) +import { defineConfig, loadEnv } from 'vite'; +import { viteStaticCopy } from 'vite-plugin-static-copy'; + +export default defineConfig(({ mode }) => ({ + test: { + globals: true, + environment: 'jsdom', + setupFiles: ['./setup.ts'], + coverage: { + reporter: ['text', 'json', 'html'], + exclude: ['setup.ts', 'testUtils.ts'], + }, + env: loadEnv(mode, "", "PUTER_"), + }, + plugins: [ + viteStaticCopy({ + targets: [ + { src: '../src/puter-js/src/index.js', dest: 'puter-js' }, + ], + }), + ], +})); \ No newline at end of file