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
125 changes: 110 additions & 15 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
### Development
# Development

To work on the SDK generator you need to do the following:

Expand All @@ -12,40 +12,135 @@ In production the root folder will be used.

As of v1.9.0 this repository uses [conventional commit messages](https://conventionalcommits.org).

### Testing
# Testing

The project uses [Vitest](https://vitest.dev/) as its test framework. Tests are colocated with their source files in the `src/` directory. Each test file is named `<module>.spec.ts` and placed next to the module it tests.
The project uses [Vitest](https://vitest.dev/) as its test framework and tests are divided into generator tests and SDK tests. Generator tests are run on the generator itself, while SDK tests are run on the generated SDK.

#### Running tests
## Generator tests

Generator tests are colocated with their source files in the `src/` directory. Each test file is named `<module>.spec.ts` and placed next to the module it tests.

### Writing generator tests

Generator test files should be placed next to the source file they test, within the `src/` directory. Each test file should be named `<module>.spec.ts`. The path aliases from `tsconfig.node.json` (e.g. `@ts/`, `@utils/`) are available in test files via `vitest.config.ts`.

Example (`src/utils/myModule.spec.ts`):

```ts
import { describe, expect, it } from 'vitest';
import { myFunction } from '@utils/myModule';

describe('myFunction', () => {
it('should return the expected result', () => {
expect(myFunction('input')).toBe('expected output');
});
});
```

### Running generator tests

```sh
# Run all tests once
$ npm run test
$ npm run test:generator

# Run tests with coverage report
$ npm run test:coverage
```

#### Writing tests
## SDK tests

Test files should be placed next to the source file they test, within the `src/` directory. Each test file should be named `<module>.spec.ts`.
SDK tests are run against the generated SDK itself. They live in the `test/` directory and are organized by feature and API version.

The path aliases from `tsconfig.node.json` (e.g. `@ts/`, `@utils/`) are available in test files via `vitest.config.ts`.
```
test/
<feature>/ # e.g. unparameterized, use-query-language, deprecated, target/browser-rx
<version>/ # e.g. v3
*.spec.ts
```

Example (`src/utils/myModule.spec.ts`):
Each feature directory corresponds to a SDK generation flag (e.g. `--use-query-language`, `--deprecated`, `--generate-unique`, `--target`). Not all features have tests yet, but new test files will be added over time.

### Writing SDK tests

SDK test files are placed under `test/<feature>/<version>/`, named `<name>.spec.ts` and import directly from the generated SDK via the `@sdk/dist` path alias.

Example (`test/unparameterized/v3/my-feature.spec.ts`):

```ts
import { describe, expect, it } from 'vitest';
import { myFunction } from '@utils/myModule';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { articleService, setGlobalConfig } from '@sdk/dist';

describe('my feature', () => {
let capturedRequest: Request;

beforeAll(() => {
setGlobalConfig({
host: 'test.example.com',
secure: true,
key: 'test-key',
interceptors: {
request: (request) => {
capturedRequest = request;
return new Response(JSON.stringify({ result: [], referencedEntities: {}, additionalProperties: {} }), {
status: 200,
headers: { 'content-type': 'application/json' }
});
}
}
});
});

describe('myFunction', () => {
it('should return the expected result', () => {
expect(myFunction('input')).toBe('expected output');
it('should do something', async () => {
await articleService().some({});
const url = new URL(capturedRequest.url);
expect(url.searchParams.get('someParam')).toBe('expectedValue');
});

afterAll(() => {
setGlobalConfig(undefined);
});
});
```

### Publishing
### Type checking

Type checking for SDK tests is performed by `tsc` as part of the test run. Because each test run targets a specific set of feature/version folders, the TypeScript config used for type-checking is generated dynamically on the fly by `scripts/run-test-configuration.js` and written to `tsconfig.typecheck-generated.json` before `tsc` and `vitest` are invoked.

The generated file looks like this:

```json
{
"extends": "./tsconfig.node.json",
"include": ["test/<feature>/<version>/**/*.spec.ts"]
}
```

`tsconfig.typecheck-generated.json` is checked into the repository as a stub (with an empty `include` array) so that `tsconfig.json` can reference it permanently. This is required for `npm run build` to succeed and for `vite-tsconfig-paths` to correctly resolve the `@sdk/*` path alias at test runtime. The stub is overwritten each time the test script runs and should not be edited manually.

### Running SDK tests

SDK tests are run via `scripts/run-test-configuration.js`, which generates the SDK for the given configuration and then type-checks and runs only the matching test folders.

```sh
# Run the default configuration (v3, browser target, no extra flags)
$ node scripts/run-test-configuration.js --version v3

# Run with a specific target
$ node scripts/run-test-configuration.js --version v3 --target node

# Run with optional feature flags
$ node scripts/run-test-configuration.js --version v3 --use-query-language
$ node scripts/run-test-configuration.js --version v3 --deprecated
$ node scripts/run-test-configuration.js --version v3 --generate-unique

# Flags can be combined
$ node scripts/run-test-configuration.js --version v3 --target browser.rx --use-query-language

# Run the default CI configuration
$ npm run ci:test
```

# Publishing

1. Switch to master branch
2. To make a new version use script `npm run release` in local terminal
Expand Down
68 changes: 56 additions & 12 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ jobs:
name: build
path: dist

test:
name: Test
generate:
name: Generate SDK
runs-on: ubuntu-latest
needs: build
strategy:
matrix:
target: [node, node.rx, browser, browser.rx]
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -49,16 +53,56 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Run tests
run: npm run test
- name: Download dist files
uses: actions/download-artifact@v4
with:
name: build
path: dist

generate:
name: Generate SDK
- name: Generate SDK
run: |
chmod +x ./bin/cli.js
./bin/cli.js test/openapi.json --target ${{ matrix.target }}
./bin/cli.js test/openapi_v2.json --target ${{ matrix.target }}
./bin/cli.js test/openapi_v3.json --target ${{ matrix.target }}

test_generator:
name: Generator test
runs-on: ubuntu-latest
needs: build

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24.11.1

- name: Install dependencies
run: npm ci

- name: Download dist files
uses: actions/download-artifact@v4
with:
name: build
path: dist

- name: Run generator tests
run: npm run test:generator

test:
name: Test
runs-on: ubuntu-latest
needs: build
strategy:
matrix:
target: [node, node.rx, browser, browser.rx]
version: [v3]
combo:
- ''
- '--use-query-language'

steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -77,11 +121,11 @@ jobs:
name: build
path: dist

- name: Generate SDK
run: |
chmod +x ./bin/cli.js
./bin/cli.js test/openapi.json --target ${{ matrix.target }}
./bin/cli.js test/openapi_v2.json --target ${{ matrix.target }}
- name: Make Generate SDK executable
run: chmod +x ./bin/cli.js

- name: Run tests
run: node ./scripts/run-test-configuration.js --version ${{ matrix.version }} ${{ matrix.combo }}

publish:
name: Publish release version
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,14 +349,22 @@ wServices['article'].some({
where: {
AND: [
{
OR: [{ name: { LIKE: '%test%', lower: true } }, { articleNumber: { LIKE: '%345%' } }]
OR: [{ name: { LIKE: '%test%', LOWER: true } }, { articleNumber: { LIKE: '%345%' } }]
},
{ batchNumberRequired: { EQ: true } }
]
}
});
```

Some API operations like the arithmetic ones are not supported as type, due to their complexity. In this case a raw filter expression can be passed as string to `where`

```ts
wServices['article'].some({
where: '(articleLength * articleWidth * articleHeight) <= 3000'
});
```

"where" parameters are ANDed with other filter parameters.

It is also possible to set an empty list within an IN-query:
Expand Down
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import tsEslint from 'typescript-eslint';
export default tsEslint.config(
{
name: 'app/files-to-ignore',
ignores: ['**/*.d.ts', '**/.*', '**/dist', '**/sdk', '**/node_modules']
ignores: ['**/*.d.ts', '**/.*', '**/dist', '**/sdk', '**/node_modules', 'test/**']
},
{
extends: [...tsEslint.configs.recommendedTypeChecked],
Expand Down
Loading
Loading