From e8d7b7b26923f0adf9c651e8ae8d53fb3edbdbb5 Mon Sep 17 00:00:00 2001 From: geisterfurz007 Date: Sat, 28 Oct 2023 15:22:08 +0200 Subject: [PATCH 1/5] feat: node tests --- src/SDK/Language/Node.php | 27 ++- templates/node/package.json.twig | 3 +- templates/node/test/id.test.js.twig | 6 + templates/node/test/permission.test.js.twig | 10 ++ templates/node/test/query.test.js.twig | 155 ++++++++++++++++++ templates/node/test/role.test.js.twig | 14 ++ .../node/test/services/service.test.js.twig | 38 +++++ 7 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 templates/node/test/id.test.js.twig create mode 100644 templates/node/test/permission.test.js.twig create mode 100644 templates/node/test/query.test.js.twig create mode 100644 templates/node/test/role.test.js.twig create mode 100644 templates/node/test/services/service.test.js.twig diff --git a/src/SDK/Language/Node.php b/src/SDK/Language/Node.php index 34518b85d7..29f8169eae 100644 --- a/src/SDK/Language/Node.php +++ b/src/SDK/Language/Node.php @@ -2,7 +2,7 @@ namespace Appwrite\SDK\Language; -class Node extends Web +class Node extends JS { /** * @return string @@ -145,21 +145,41 @@ public function getFiles(): array 'destination' => 'src/models.ts', 'template' => 'web/src/models.ts.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/permission.test.js', + 'template' => 'node/test/permission.test.js.twig', + ], [ 'scope' => 'default', 'destination' => 'src/permission.ts', 'template' => 'web/src/permission.ts.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/role.test.js', + 'template' => 'node/test/role.test.js.twig', + ], [ 'scope' => 'default', 'destination' => 'src/role.ts', 'template' => 'web/src/role.ts.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/id.test.js', + 'template' => 'node/test/id.test.js.twig', + ], [ 'scope' => 'default', 'destination' => 'src/id.ts', 'template' => 'web/src/id.ts.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/query.test.js', + 'template' => 'node/test/query.test.js.twig', + ], [ 'scope' => 'default', 'destination' => 'src/query.ts', @@ -170,6 +190,11 @@ public function getFiles(): array 'destination' => 'src/operator.ts', 'template' => 'node/src/operator.ts.twig', ], + [ + 'scope' => 'service', + 'destination' => '/test/services/{{service.name | caseDash}}.test.js', + 'template' => 'node/test/services/service.test.js.twig', + ], [ 'scope' => 'default', 'destination' => 'README.md', diff --git a/templates/node/package.json.twig b/templates/node/package.json.twig index 39f1faa5ea..bf51b41924 100644 --- a/templates/node/package.json.twig +++ b/templates/node/package.json.twig @@ -46,7 +46,8 @@ "tsup": "7.2.0", "esbuild-plugin-file-path-extensions": "^2.0.0", "tslib": "2.6.2", - "typescript": "5.4.2" + "typescript": "5.4.2", + "jest": "^29.7.0" }, "dependencies": { "json-bigint": "1.0.0", diff --git a/templates/node/test/id.test.js.twig b/templates/node/test/id.test.js.twig new file mode 100644 index 0000000000..d28fab758d --- /dev/null +++ b/templates/node/test/id.test.js.twig @@ -0,0 +1,6 @@ +const ID = require("../lib/id"); + +describe("ID", () => { + test('unique', () => expect(ID.unique()).toEqual('unique()')); + test('custom', () => expect(ID.custom('custom')).toEqual('custom')); +}); diff --git a/templates/node/test/permission.test.js.twig b/templates/node/test/permission.test.js.twig new file mode 100644 index 0000000000..8fb854e783 --- /dev/null +++ b/templates/node/test/permission.test.js.twig @@ -0,0 +1,10 @@ +const Permission = require("../lib/permission"); +const Role = require("../lib/role"); + +describe('Permission', () => { + test('read', () => expect(Permission.read(Role.any())).toEqual('read("any")')); + test('write', () => expect(Permission.write(Role.any())).toEqual('write("any")')); + test('create', () => expect(Permission.create(Role.any())).toEqual('create("any")')); + test('update', () => expect(Permission.update(Role.any())).toEqual('update("any")')); + test('delete', () => expect(Permission.delete(Role.any())).toEqual('delete("any")')); +}) diff --git a/templates/node/test/query.test.js.twig b/templates/node/test/query.test.js.twig new file mode 100644 index 0000000000..c1dd7e6328 --- /dev/null +++ b/templates/node/test/query.test.js.twig @@ -0,0 +1,155 @@ +const Query = require("../lib/query"); + +const tests = [ + { + description: 'with a string', + value: 's', + expectedValues: '["s"]' + }, + { + description: 'with a integer', + value: 1, + expectedValues: '[1]' + }, + { + description: 'with a double', + value: 1.2, + expectedValues: '[1.2]' + }, + { + description: 'with a whole number double', + value: 1.0, + expectedValues: '[1]' + }, + { + description: 'with a bool', + value: false, + expectedValues: '[false]' + }, + { + description: 'with a list', + value: ['a', 'b', 'c'], + expectedValues: '["a","b","c"]' + } +]; + +describe('Query', () => { + describe('basic filter equal', () => { + for (const t of tests) { + test(t.description, () => + expect(Query.equal("attr", t.value)) + .toEqual(`equal("attr", ${t.expectedValues})`) + ) + } + }) + + describe('basic filter notEqual', () => { + for (const t of tests) { + test(t.description, () => + expect(Query.notEqual("attr", t.value)) + .toEqual(`notEqual("attr", ${t.expectedValues})`) + ) + } + }); + + describe('basic filter lessThan', () => { + for (const t of tests) { + test(t.description, () => + expect(Query.lessThan("attr", t.value)) + .toEqual(`lessThan("attr", ${t.expectedValues})`) + ) + } + }); + + describe('basic filter lessThanEqual', () => { + for (const t of tests) { + test(t.description, () => + expect(Query.lessThanEqual("attr", t.value)) + .toEqual(`lessThanEqual("attr", ${t.expectedValues})`) + ) + } + }); + + describe('basic filter greaterThan', () => { + for (const t of tests) { + test(t.description, () => + expect(Query.greaterThan("attr", t.value)) + .toEqual(`greaterThan("attr", ${t.expectedValues})`) + ) + } + }); + + describe('basic filter greaterThanEqual', () => { + for (const t of tests) { + test(t.description, () => + expect(Query.greaterThanEqual("attr", t.value)) + .toEqual(`greaterThanEqual("attr", ${t.expectedValues})`) + ) + } + }); + + test('search', () => + expect(Query.search('attr', 'keyword1 keyword2')) + .toEqual('search("attr", ["keyword1 keyword2"])') + ); + + test('isNull', () => + expect(Query.isNull('attr')) + .toEqual('isNull("attr")') + ); + + test('isNotNull', () => + expect(Query.isNotNull('attr')) + .toEqual('isNotNull("attr")') + ); + + describe('between', () => { + test('with integers', () => + expect(Query.between('attr', 1, 2)) + .toEqual('between("attr", [1,2])') + ); + test('with doubles', () => + expect(Query.between('attr', 1.2, 2.2)) + .toEqual('between("attr", [1.2,2.2])') + ); + test('with strings', () => + expect(Query.between('attr', "a", "z")) + .toEqual('between("attr", ["a","z"])') + ); + }); + + test('select', () => + expect(Query.select(['attr1', 'attr2'])) + .toEqual('select(["attr1","attr2"])') + ); + + test('orderAsc', () => + expect(Query.orderAsc('attr')) + .toEqual('orderAsc("attr")') + ); + + test('orderDesc', () => + expect(Query.orderDesc('attr')) + .toEqual('orderDesc("attr")') + ); + + test('cursorBefore', () => + expect(Query.cursorBefore('attr')) + .toEqual('cursorBefore("attr")') + ); + + test('cursorAfter', () => + expect(Query.cursorAfter('attr')) + .toEqual('cursorAfter("attr")') + ); + + test('limit', () => + expect(Query.limit(1)) + .toEqual('limit(1)') + ); + + test('offset', () => + expect(Query.offset(1)) + .toEqual('offset(1)') + ); +}) diff --git a/templates/node/test/role.test.js.twig b/templates/node/test/role.test.js.twig new file mode 100644 index 0000000000..61dd4231fb --- /dev/null +++ b/templates/node/test/role.test.js.twig @@ -0,0 +1,14 @@ +const Role = require("../lib/role"); + +describe('Role', () => { + test('any', () => expect(Role.any()).toEqual('any')); + test('user without status', () => expect(Role.user('custom')).toEqual('user:custom')); + test('user with status', () => expect(Role.user('custom', 'verified')).toEqual('user:custom/verified')); + test('users without status', () => expect(Role.users()).toEqual('users')); + test('users with status', () => expect(Role.users('verified')).toEqual('users/verified')); + test('guests', () => expect(Role.guests()).toEqual('guests')); + test('team without role', () => expect(Role.team('custom')).toEqual('team:custom')) + test('team with role', () => expect(Role.team('custom', 'owner')).toEqual('team:custom/owner')) + test('member', () => expect(Role.member('custom')).toEqual('member:custom')) + test('label', () => expect(Role.label('admin')).toEqual('label:admin')) +}) diff --git a/templates/node/test/services/service.test.js.twig b/templates/node/test/services/service.test.js.twig new file mode 100644 index 0000000000..8d77ddf5dc --- /dev/null +++ b/templates/node/test/services/service.test.js.twig @@ -0,0 +1,38 @@ +const Client = require("../../lib/client"); +const InputFile = require("../../lib/inputFile"); +const {{ service.name | caseUcfirst }} = require("../../lib/services/{{ service.name | caseCamel }}"); + +const mockedAxios = require("axios"); +jest.mock('axios', () => jest.fn()); + +describe('{{ service.name | caseUcfirst }}', () => { + const client = new Client(); + const {{ service.name | caseCamel }} = new {{ service.name | caseUcfirst }}(client); + + {% for method in service.methods ~%} + test('test method {{ method.name | caseCamel }}()', async () => { + {%~ if method.type == 'webAuth' %} + const data = ''; + {%~ elseif method.type == 'location' %} + const data = new Uint8Array(0); + {%~ else %} + {%- if method.responseModel and method.responseModel != 'any' %} + const data = { + {%- for definition in spec.definitions ~%}{%~ if definition.name == method.responseModel -%}{%~ for property in definition.properties | filter((param) => param.required) ~%} + '{{ property.name | escapeDollarSign }}': {% if property.type == 'object' %}{}{% elseif property.type == 'array' %}[]{% elseif property.type == 'string' %}'{{ property.example | escapeDollarSign }}'{% elseif property.type == 'boolean' %}true{% else %}{{ property.example }}{% endif %},{%~ endfor ~%}{% set break = true %}{%- else -%}{% set continue = true %}{%- endif -%}{%~ endfor -%} + }; + {%~ else %} + const data = ''; + {%~ endif %} + {%~ endif %} + + mockedAxios.mockImplementation(() => Promise.resolve({data: data})); + + const response = await {{ service.name | caseCamel }}.{{ method.name | caseCamel }}({%~ for parameter in method.parameters.all | filter((param) => param.required) ~%} + {% if parameter.type == 'object' %}{}{% elseif parameter.type == 'array' %}[]{% elseif parameter.type == 'file' %}InputFile.fromBuffer(new Uint8Array(0), 'image.png'){% elseif parameter.type == 'boolean' %}true{% elseif parameter.type == 'string' %}'{% if parameter.example is not empty %}{{ parameter.example | escapeDollarSign }}{% endif %}'{% elseif parameter.type == 'integer' and parameter['x-example'] is empty %}1{% elseif parameter.type == 'number' and parameter['x-example'] is empty %}1.0{% else %}{{ parameter.example }}{%~ endif ~%},{%~ endfor ~%} + ); + + expect(response).toEqual(data); + }); + {% endfor %} +}) From 58da2dfe99367660b6f7898504ab4a78e6e57673 Mon Sep 17 00:00:00 2001 From: geisterfurz007 Date: Sun, 19 Nov 2023 16:38:10 +0100 Subject: [PATCH 2/5] fix: updated between serialization --- templates/node/test/query.test.js.twig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/node/test/query.test.js.twig b/templates/node/test/query.test.js.twig index c1dd7e6328..0dff5eb5fa 100644 --- a/templates/node/test/query.test.js.twig +++ b/templates/node/test/query.test.js.twig @@ -106,15 +106,15 @@ describe('Query', () => { describe('between', () => { test('with integers', () => expect(Query.between('attr', 1, 2)) - .toEqual('between("attr", [1,2])') + .toEqual('between("attr", 1, 2)') ); test('with doubles', () => expect(Query.between('attr', 1.2, 2.2)) - .toEqual('between("attr", [1.2,2.2])') + .toEqual('between("attr", 1.2, 2.2)') ); test('with strings', () => expect(Query.between('attr', "a", "z")) - .toEqual('between("attr", ["a","z"])') + .toEqual('between("attr", "a" "z")') ); }); From de8647186b6b4dcdc67c8c51099d2c808b689034 Mon Sep 17 00:00:00 2001 From: geisterfurz007 Date: Tue, 10 Mar 2026 23:57:11 +0100 Subject: [PATCH 3/5] chore: fix tests --- src/SDK/Language/Node.php | 6 +-- src/SDK/SDK.php | 2 +- templates/node/src/client.ts.twig | 2 +- templates/node/test/id.test.js.twig | 4 +- templates/node/test/permission.test.js.twig | 4 +- templates/node/test/query.test.js.twig | 42 +++++++++---------- templates/node/test/role.test.js.twig | 2 +- .../node/test/services/service.test.js.twig | 24 ++++++----- 8 files changed, 45 insertions(+), 41 deletions(-) diff --git a/src/SDK/Language/Node.php b/src/SDK/Language/Node.php index 29f8169eae..02c81d25f1 100644 --- a/src/SDK/Language/Node.php +++ b/src/SDK/Language/Node.php @@ -2,7 +2,7 @@ namespace Appwrite\SDK\Language; -class Node extends JS +class Node extends Web { /** * @return string @@ -192,7 +192,7 @@ public function getFiles(): array ], [ 'scope' => 'service', - 'destination' => '/test/services/{{service.name | caseDash}}.test.js', + 'destination' => 'test/services/{{service.name | caseDash}}.test.js', 'template' => 'node/test/services/service.test.js.twig', ], [ @@ -223,7 +223,7 @@ public function getFiles(): array [ 'scope' => 'default', 'destination' => 'tsconfig.json', - 'template' => '/node/tsconfig.json.twig', + 'template' => 'node/tsconfig.json.twig', ], [ 'scope' => 'default', diff --git a/src/SDK/SDK.php b/src/SDK/SDK.php index a537e066f6..028c4a50cd 100644 --- a/src/SDK/SDK.php +++ b/src/SDK/SDK.php @@ -176,7 +176,7 @@ public function __construct(Language $language, Spec $spec) return implode("\n", $value); }, ['is_safe' => ['html']])); $this->twig->addFilter(new TwigFilter('escapeDollarSign', function ($value) { - $value = str_replace('\\', '\\\\', $value); // Escape backslashes first + $value = str_replace('\\', '\\\\', $value ?? ''); // Escape backslashes first $value = str_replace('"', '\\"', $value); // Escape double quotes $value = str_replace('$', '\\$', $value); // Escape dollar signs return $value; diff --git a/templates/node/src/client.ts.twig b/templates/node/src/client.ts.twig index 19c387f428..a94cbb6de8 100644 --- a/templates/node/src/client.ts.twig +++ b/templates/node/src/client.ts.twig @@ -79,7 +79,7 @@ function getUserAgent() { const platform: string[] = []; if (typeof process !== 'undefined') { if (typeof process.platform === 'string') platform.push(process.platform); - if (typeof process.arch === 'string') platform.push(process.arch); + if (typeof process.arch = ?? ''== 'string') platform.push(process.arch); } if (platform.length > 0) { ua += ` (${platform.join('; ')})`; diff --git a/templates/node/test/id.test.js.twig b/templates/node/test/id.test.js.twig index d28fab758d..0a648bc1b8 100644 --- a/templates/node/test/id.test.js.twig +++ b/templates/node/test/id.test.js.twig @@ -1,6 +1,6 @@ -const ID = require("../lib/id"); +const { ID } = require("../dist/id"); describe("ID", () => { - test('unique', () => expect(ID.unique()).toEqual('unique()')); + test('unique', () => expect(ID.unique()).toHaveLength(20)); test('custom', () => expect(ID.custom('custom')).toEqual('custom')); }); diff --git a/templates/node/test/permission.test.js.twig b/templates/node/test/permission.test.js.twig index 8fb854e783..7f972d3b2d 100644 --- a/templates/node/test/permission.test.js.twig +++ b/templates/node/test/permission.test.js.twig @@ -1,5 +1,5 @@ -const Permission = require("../lib/permission"); -const Role = require("../lib/role"); +const { Permission } = require("../dist/permission"); +const { Role } = require("../dist/role"); describe('Permission', () => { test('read', () => expect(Permission.read(Role.any())).toEqual('read("any")')); diff --git a/templates/node/test/query.test.js.twig b/templates/node/test/query.test.js.twig index 0dff5eb5fa..e539a1f606 100644 --- a/templates/node/test/query.test.js.twig +++ b/templates/node/test/query.test.js.twig @@ -1,4 +1,4 @@ -const Query = require("../lib/query"); +const { Query } = require("../dist/query"); const tests = [ { @@ -38,7 +38,7 @@ describe('Query', () => { for (const t of tests) { test(t.description, () => expect(Query.equal("attr", t.value)) - .toEqual(`equal("attr", ${t.expectedValues})`) + .toEqual(`{"method":"equal","attribute":"attr","values":${t.expectedValues}}`) ) } }) @@ -47,7 +47,7 @@ describe('Query', () => { for (const t of tests) { test(t.description, () => expect(Query.notEqual("attr", t.value)) - .toEqual(`notEqual("attr", ${t.expectedValues})`) + .toEqual(`{"method":"notEqual","attribute":"attr","values":${t.expectedValues}}`) ) } }); @@ -56,7 +56,7 @@ describe('Query', () => { for (const t of tests) { test(t.description, () => expect(Query.lessThan("attr", t.value)) - .toEqual(`lessThan("attr", ${t.expectedValues})`) + .toEqual(`{"method":"lessThan","attribute":"attr","values":${t.expectedValues}}`) ) } }); @@ -65,7 +65,7 @@ describe('Query', () => { for (const t of tests) { test(t.description, () => expect(Query.lessThanEqual("attr", t.value)) - .toEqual(`lessThanEqual("attr", ${t.expectedValues})`) + .toEqual(`{"method":"lessThanEqual","attribute":"attr","values":${t.expectedValues}}`) ) } }); @@ -74,7 +74,7 @@ describe('Query', () => { for (const t of tests) { test(t.description, () => expect(Query.greaterThan("attr", t.value)) - .toEqual(`greaterThan("attr", ${t.expectedValues})`) + .toEqual(`{"method":"greaterThan","attribute":"attr","values":${t.expectedValues}}`) ) } }); @@ -83,73 +83,73 @@ describe('Query', () => { for (const t of tests) { test(t.description, () => expect(Query.greaterThanEqual("attr", t.value)) - .toEqual(`greaterThanEqual("attr", ${t.expectedValues})`) + .toEqual(`{"method":"greaterThanEqual","attribute":"attr","values":${t.expectedValues}}`) ) } }); test('search', () => expect(Query.search('attr', 'keyword1 keyword2')) - .toEqual('search("attr", ["keyword1 keyword2"])') + .toEqual(`{"method":"search","attribute":"attr","values":["keyword1 keyword2"]}`) ); test('isNull', () => expect(Query.isNull('attr')) - .toEqual('isNull("attr")') + .toEqual(`{"method":"isNull","attribute":"attr"}`) ); test('isNotNull', () => expect(Query.isNotNull('attr')) - .toEqual('isNotNull("attr")') + .toEqual(`{"method":"isNotNull","attribute":"attr"}`) ); describe('between', () => { test('with integers', () => expect(Query.between('attr', 1, 2)) - .toEqual('between("attr", 1, 2)') + .toEqual(`{"method":"between","attribute":"attr","values":[1,2]}`) ); test('with doubles', () => expect(Query.between('attr', 1.2, 2.2)) - .toEqual('between("attr", 1.2, 2.2)') + .toEqual(`{"method":"between","attribute":"attr","values":[1.2,2.2]}`) ); test('with strings', () => - expect(Query.between('attr', "a", "z")) - .toEqual('between("attr", "a" "z")') + expect(Query.between('attr',"a","z")) + .toEqual(`{"method":"between","attribute":"attr","values":["a","z"]}`) ); }); test('select', () => expect(Query.select(['attr1', 'attr2'])) - .toEqual('select(["attr1","attr2"])') + .toEqual(`{"method":"select","values":["attr1","attr2"]}`) ); test('orderAsc', () => expect(Query.orderAsc('attr')) - .toEqual('orderAsc("attr")') + .toEqual(`{"method":"orderAsc","attribute":"attr"}`) ); test('orderDesc', () => expect(Query.orderDesc('attr')) - .toEqual('orderDesc("attr")') + .toEqual(`{"method":"orderDesc","attribute":"attr"}`) ); test('cursorBefore', () => expect(Query.cursorBefore('attr')) - .toEqual('cursorBefore("attr")') + .toEqual('{"method":"cursorBefore","values":["attr"]}') ); test('cursorAfter', () => expect(Query.cursorAfter('attr')) - .toEqual('cursorAfter("attr")') + .toEqual('{"method":"cursorAfter","values":["attr"]}') ); test('limit', () => expect(Query.limit(1)) - .toEqual('limit(1)') + .toEqual('{"method":"limit","values":[1]}') ); test('offset', () => expect(Query.offset(1)) - .toEqual('offset(1)') + .toEqual('{"method":"offset","values":[1]}') ); }) diff --git a/templates/node/test/role.test.js.twig b/templates/node/test/role.test.js.twig index 61dd4231fb..8f7420bda5 100644 --- a/templates/node/test/role.test.js.twig +++ b/templates/node/test/role.test.js.twig @@ -1,4 +1,4 @@ -const Role = require("../lib/role"); +const { Role } = require("../dist/role"); describe('Role', () => { test('any', () => expect(Role.any()).toEqual('any')); diff --git a/templates/node/test/services/service.test.js.twig b/templates/node/test/services/service.test.js.twig index 8d77ddf5dc..fd842cd90b 100644 --- a/templates/node/test/services/service.test.js.twig +++ b/templates/node/test/services/service.test.js.twig @@ -1,9 +1,9 @@ -const Client = require("../../lib/client"); -const InputFile = require("../../lib/inputFile"); -const {{ service.name | caseUcfirst }} = require("../../lib/services/{{ service.name | caseCamel }}"); +const { Client } = require("../../dist/client"); +const { InputFile } = require("../../dist/inputFile"); +const { {{ service.name | caseUcfirst }} } = require("../../dist/services/{{ service.name | caseKebab }}"); -const mockedAxios = require("axios"); -jest.mock('axios', () => jest.fn()); +const { fetch: mockedFetch, Response } = require("node-fetch-native-with-agent"); +jest.mock('node-fetch-native-with-agent', () => ({ ...jest.requireActual('node-fetch-native-with-agent'), fetch: jest.fn() })); describe('{{ service.name | caseUcfirst }}', () => { const client = new Client(); @@ -12,9 +12,11 @@ describe('{{ service.name | caseUcfirst }}', () => { {% for method in service.methods ~%} test('test method {{ method.name | caseCamel }}()', async () => { {%~ if method.type == 'webAuth' %} - const data = ''; + const data = 'https://example.com/'; + mockedFetch.mockImplementation(() => Response.redirect(data)); {%~ elseif method.type == 'location' %} - const data = new Uint8Array(0); + const data = new ArrayBuffer(0); + mockedFetch.mockImplementation(() => new Response(data)); {%~ else %} {%- if method.responseModel and method.responseModel != 'any' %} const data = { @@ -22,16 +24,18 @@ describe('{{ service.name | caseUcfirst }}', () => { '{{ property.name | escapeDollarSign }}': {% if property.type == 'object' %}{}{% elseif property.type == 'array' %}[]{% elseif property.type == 'string' %}'{{ property.example | escapeDollarSign }}'{% elseif property.type == 'boolean' %}true{% else %}{{ property.example }}{% endif %},{%~ endfor ~%}{% set break = true %}{%- else -%}{% set continue = true %}{%- endif -%}{%~ endfor -%} }; {%~ else %} - const data = ''; + const data = {message: ""}; {%~ endif %} + mockedFetch.mockImplementation(() => Response.json(data)); {%~ endif %} - mockedAxios.mockImplementation(() => Promise.resolve({data: data})); - const response = await {{ service.name | caseCamel }}.{{ method.name | caseCamel }}({%~ for parameter in method.parameters.all | filter((param) => param.required) ~%} {% if parameter.type == 'object' %}{}{% elseif parameter.type == 'array' %}[]{% elseif parameter.type == 'file' %}InputFile.fromBuffer(new Uint8Array(0), 'image.png'){% elseif parameter.type == 'boolean' %}true{% elseif parameter.type == 'string' %}'{% if parameter.example is not empty %}{{ parameter.example | escapeDollarSign }}{% endif %}'{% elseif parameter.type == 'integer' and parameter['x-example'] is empty %}1{% elseif parameter.type == 'number' and parameter['x-example'] is empty %}1.0{% else %}{{ parameter.example }}{%~ endif ~%},{%~ endfor ~%} ); + // Remove custom toString method on the objects to allow for clean data comparison. + delete response.toString; + expect(response).toEqual(data); }); {% endfor %} From a85d92fcfc311ff44b4861748efdf1711fde8b3a Mon Sep 17 00:00:00 2001 From: geisterfurz007 Date: Wed, 11 Mar 2026 19:37:24 +0100 Subject: [PATCH 4/5] chore: add operator.test.js / fix build error --- src/SDK/Language/Node.php | 5 ++ templates/node/src/client.ts.twig | 2 +- templates/node/test/operator.test.js.twig | 99 +++++++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 templates/node/test/operator.test.js.twig diff --git a/src/SDK/Language/Node.php b/src/SDK/Language/Node.php index 02c81d25f1..fbbbea9246 100644 --- a/src/SDK/Language/Node.php +++ b/src/SDK/Language/Node.php @@ -185,6 +185,11 @@ public function getFiles(): array 'destination' => 'src/query.ts', 'template' => 'web/src/query.ts.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/operator.test.js', + 'template' => 'node/test/operator.test.js.twig', + ], [ 'scope' => 'default', 'destination' => 'src/operator.ts', diff --git a/templates/node/src/client.ts.twig b/templates/node/src/client.ts.twig index a94cbb6de8..19c387f428 100644 --- a/templates/node/src/client.ts.twig +++ b/templates/node/src/client.ts.twig @@ -79,7 +79,7 @@ function getUserAgent() { const platform: string[] = []; if (typeof process !== 'undefined') { if (typeof process.platform === 'string') platform.push(process.platform); - if (typeof process.arch = ?? ''== 'string') platform.push(process.arch); + if (typeof process.arch === 'string') platform.push(process.arch); } if (platform.length > 0) { ua += ` (${platform.join('; ')})`; diff --git a/templates/node/test/operator.test.js.twig b/templates/node/test/operator.test.js.twig new file mode 100644 index 0000000000..408723a318 --- /dev/null +++ b/templates/node/test/operator.test.js.twig @@ -0,0 +1,99 @@ +const { Condition, Operator } = require("../dist/operator"); + +describe('Operator', () => { + test('returns increment', () => { + expect(Operator.increment(1)).toEqual(`{"method":"increment","values":[1]}`); + }); + + test('returns increment with max', () => { + expect(Operator.increment(5, 100)).toEqual(`{"method":"increment","values":[5,100]}`); + }); + + test('returns decrement', () => { + expect(Operator.decrement(1)).toEqual(`{"method":"decrement","values":[1]}`); + }); + + test('returns decrement with min', () => { + expect(Operator.decrement(3, 0)).toEqual(`{"method":"decrement","values":[3,0]}`); + }); + + test('returns multiply', () => { + expect(Operator.multiply(2)).toEqual(`{"method":"multiply","values":[2]}`); + }); + + test('returns multiply with max', () => { + expect(Operator.multiply(3, 1000)).toEqual(`{"method":"multiply","values":[3,1000]}`); + }); + + test('returns divide', () => { + expect(Operator.divide(2)).toEqual(`{"method":"divide","values":[2]}`); + }); + + test('returns divide with min', () => { + expect(Operator.divide(4, 1)).toEqual(`{"method":"divide","values":[4,1]}`); + }); + + test('returns modulo', () => { + expect(Operator.modulo(5)).toEqual(`{"method":"modulo","values":[5]}`); + }); + + test('returns power', () => { + expect(Operator.power(2)).toEqual(`{"method":"power","values":[2]}`); + }); + + test('returns arrayAppend', () => { + expect(Operator.arrayAppend(['item1', 'item2'])).toEqual('{"method":"arrayAppend","values":["item1","item2"]}'); + }); + + test('returns arrayPrepend', () => { + expect(Operator.arrayPrepend(['first', 'second'])).toEqual('{"method":"arrayPrepend","values":["first","second"]}'); + }); + + test('returns arrayInsert', () => { + expect(Operator.arrayInsert(0, 'newItem')).toEqual('{"method":"arrayInsert","values":[0,"newItem"]}'); + }); + + test('returns arrayRemove', () => { + expect(Operator.arrayRemove('oldItem')).toEqual('{"method":"arrayRemove","values":["oldItem"]}'); + }); + + test('returns arrayUnique', () => { + expect(Operator.arrayUnique()).toEqual('{"method":"arrayUnique","values":[]}'); + }); + + test('returns arrayIntersect', () => { + expect(Operator.arrayIntersect(['a', 'b', 'c'])).toEqual('{"method":"arrayIntersect","values":["a","b","c"]}'); + }); + + test('returns arrayDiff', () => { + expect(Operator.arrayDiff(['x', 'y'])).toEqual('{"method":"arrayDiff","values":["x","y"]}'); + }); + + test('returns arrayFilter', () => { + expect(Operator.arrayFilter(Condition.Equal, 'test')).toEqual('{"method":"arrayFilter","values":["equal","test"]}'); + }); + + test('returns stringConcat', () => { + expect(Operator.stringConcat('suffix')).toEqual('{"method":"stringConcat","values":["suffix"]}'); + }); + + test('returns stringReplace', () => { + expect(Operator.stringReplace('old', 'new')).toEqual('{"method":"stringReplace","values":["old","new"]}'); + }); + + test('returns toggle', () => { + expect(Operator.toggle()).toEqual('{"method":"toggle","values":[]}'); + }); + + test('returns dateAddDays', () => { + expect(Operator.dateAddDays(7)).toEqual('{"method":"dateAddDays","values":[7]}'); + }); + + test('returns dateSubDays', () => { + expect(Operator.dateSubDays(7)).toEqual('{"method":"dateSubDays","values":[7]}'); + }); + + test('returns dateSetNow', () => { + expect(Operator.dateSetNow()).toEqual('{"method":"dateSetNow","values":[]}'); + }); +}); From 72731b62ec5da1e5a90c46084ad06fe45057ecdf Mon Sep 17 00:00:00 2001 From: geisterfurz007 Date: Sat, 21 Mar 2026 00:31:51 +0100 Subject: [PATCH 5/5] feat: run node tests in CI --- .github/workflows/sdk-build-validation.yml | 7 ++++++- templates/node/package.json.twig | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sdk-build-validation.yml b/.github/workflows/sdk-build-validation.yml index d33b3b5bbd..20a1ede63b 100644 --- a/.github/workflows/sdk-build-validation.yml +++ b/.github/workflows/sdk-build-validation.yml @@ -153,7 +153,7 @@ jobs: working-directory: examples/${{ matrix.sdk }} run: | case "${{ matrix.sdk }}" in - web|node) + web) npm install npm run build ;; @@ -200,6 +200,11 @@ jobs: ruby) bundle install ;; + node) + npm install + npm run build + npm run test + ;; dart) dart pub get dart analyze --no-fatal-warnings diff --git a/templates/node/package.json.twig b/templates/node/package.json.twig index bf51b41924..88b26fb459 100644 --- a/templates/node/package.json.twig +++ b/templates/node/package.json.twig @@ -7,7 +7,8 @@ "main": "dist/index.js", "type": "commonjs", "scripts": { - "build": "tsup" + "build": "tsup", + "test": "jest" }, "exports": { ".": {