Skip to content

Commit

Permalink
fix(#zimic): exit process after stopping the interceptor server throu…
Browse files Browse the repository at this point in the history
…gh CLI (#295)

### Fixes
- [#zimic] Added a call to `process.exit(0)` after an interceptor server
is stopped in ephemeral mode. This is to make sure that the process does
not hangs, even though the server has been stopped. It is not clear to
me how hanging happens, but it rarely does in the tests of
`zimic-test-client`.

### Documentation
- [#zimic] Included `process.exit(0)` to the documentation about
interceptor server programmatic usage.
- [#zimic] Fixed a code snippet still using `runCommand`, which is no
longer available in >=v0.8.
  • Loading branch information
diego-aquino committed Jul 14, 2024
1 parent ccb8929 commit bb2af96
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 33 deletions.
28 changes: 13 additions & 15 deletions .github/actions/zimic-setup/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ inputs:

outputs:
install-filters:
description: Effective filter flags for installing dependencies
description: Filter flags of the packages included in the install step
value: ${{ steps.install-dependencies.outputs.install-filters }}
build-filters:
description: Effective filter flags for building dependencies
description: Filter flags of the packages included in the build step
value: ${{ steps.build-dependencies.outputs.build-filters }}

runs:
Expand Down Expand Up @@ -77,29 +77,27 @@ runs:
}
if [[ '${{ inputs.install }}' == '' ]]; then
workspaceRootInstallFlag=''
partialInstallFlag=''
installFlag=''
installFilters=''
fullInstallFilters=''
else
workspaceRootInstallFlag='--filter zimic-root'
partialInstallFlag="$(composeFilterOptions ${{ inputs.install }})"
installFlag="$workspaceRootInstallFlag $partialInstallFlag"
installFilters="$(composeFilterOptions ${{ inputs.install }})"
fullInstallFilters="--filter zimic-root --filter zimic $installFilters"
fi
echo "install-filters=$partialInstallFlag" >> $GITHUB_OUTPUT
pnpm install --prefer-offline --frozen-lockfile --ignore-scripts $installFlag
echo "install-filters=$installFilters" >> $GITHUB_OUTPUT
pnpm install --prefer-offline --frozen-lockfile --ignore-scripts $fullInstallFilters
if [[ '${{ inputs.build }}' == '' ]]; then
buildFlag=''
buildFilters=''
else
buildFlag="$(composeFilterOptions ${{ inputs.build }})"
buildFilters="$(composeFilterOptions ${{ inputs.build }})"
fi
echo "build-filters=$buildFlag" >> $GITHUB_OUTPUT
pnpm turbo build $buildFlag
echo "build-filters=$buildFilters" >> $GITHUB_OUTPUT
pnpm turbo build $buildFilters
# apply the build outputs of the internal packages
pnpm install --offline $installFlag
pnpm install --offline $fullInstallFilters
if [[ '${{ inputs.install-playwright-browsers }}' == 'true' ]]; then
pnpm --dir packages/zimic deps:install-playwright
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ env:
${{ !(github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main') && secrets.TURBO_REMOTE_CACHE_TEAM || '' }}
TURBO_LOG_ORDER: stream
INSTALL_OPTIONS: |
${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'main' && 'zimic "...[HEAD^1]"' || '' }}
${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'main' && '"...[HEAD^1]"' || '' }}
BUILD_OPTIONS: |
${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'main' && 'zimic "{./apps/*}[HEAD^1]^..." "{./packages/*} [HEAD^1]..."' || './packages/*' }}
${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'main' && '"{./apps/*}[HEAD^1]^..." "{./packages/*}[HEAD^1]..."' || './packages/*' }}
jobs:
ci-general:
Expand All @@ -45,8 +45,8 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
turbo-token: ${{ env.TURBO_TOKEN }}
turbo-team: ${{ env.TURBO_TEAM }}
install: ${{ env.INSTALL_OPTIONS }}
build: ${{ env.BUILD_OPTIONS }}
install: ${{ env.INSTALL_OPTIONS == '' && '' || format('zimic {0}', env.INSTALL_OPTIONS) }}
build: ${{ env.BUILD_OPTIONS == '' && '' || format('zimic {0}', env.BUILD_OPTIONS) }}
install-playwright-browsers: true

- name: Check formatting style
Expand Down
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2739,17 +2739,23 @@ should automatically stop after the command finishes.
The module `zimic/server` exports resources for managing interceptor servers programmatically. Even though we recommend
using the CLI, this module is a valid alternative for more advanced use cases.

An example using the programmatic API and [`execa`](https://www.npmjs.com/package/execa) to run a command when the
server is ready:

```ts
import { createInterceptorServer, runCommand } from 'zimic/interceptor/server';
import { execa as $ } from 'execa';
import { interceptorServer } from 'zimic/interceptor/server';

const server = createInterceptorServer({ hostname: 'localhost', port: 3000 });
const server = interceptorServer.create({ hostname: 'localhost', port: 3000 });
await server.start();

// Run a command when the server is ready
// Run a command when the server is ready, assuming the following format:
// node <script> -- <command> [...commandArguments]
const [command, ...commandArguments] = process.argv.slice(3);
await runCommand(command, commandArguments);
await $(command, commandArguments, { stdio: 'inherit' });

await server.stop();
process.exit(0);
```

The helper function `runCommand` is useful to run a shell command in server scripts. The
Expand Down Expand Up @@ -2898,6 +2904,8 @@ zimic typegen openapi ./schema.yaml \
The module `zimic/typegen` exports resources for generating types programmatically. We recommend using the CLI, but this
module is a valid alternative for more advanced use cases.

An example using the programmatic API to generate types from an OpenAPI schema:

```ts
import { typegen } from 'zimic/typegen';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { beforeAll, beforeEach, afterAll, expect, describe, it, expectTypeOf } from 'vitest';
import { beforeAll, beforeEach, afterAll, expect, describe, it, expectTypeOf, afterEach } from 'vitest';
import { JSONSerialized } from 'zimic0';
import { HttpRequest, HttpResponse, HttpSearchParams } from 'zimic0/http';
import { httpInterceptor, HttpInterceptorType } from 'zimic0/interceptor/http';
Expand Down Expand Up @@ -62,7 +62,7 @@ async function declareDefaultClientTests(options: ClientTestOptionsByWorkerType)
);
});

beforeEach(async () => {
afterEach(async () => {
await Promise.all(
interceptors.map(async (interceptor) => {
await interceptor.clear();
Expand Down Expand Up @@ -381,8 +381,8 @@ async function declareDefaultClientTests(options: ClientTestOptionsByWorkerType)
});

it('should list users with ordering', async () => {
const orderedUsers = users.sort((user, otherUser) => {
return -user.email.localeCompare(otherUser.email);
const usersSortedByDescendingEmail = [...users].sort((user, otherUser) => {
return otherUser.email.localeCompare(user.email);
});

const listHandler = await authInterceptor
Expand All @@ -392,7 +392,7 @@ async function declareDefaultClientTests(options: ClientTestOptionsByWorkerType)
})
.respond({
status: 200,
body: orderedUsers.map(serializeUser),
body: usersSortedByDescendingEmail.map(serializeUser),
});

const response = await listUsers({
Expand All @@ -401,7 +401,7 @@ async function declareDefaultClientTests(options: ClientTestOptionsByWorkerType)
expect(response.status).toBe(200);

const returnedUsers = (await response.json()) as User[];
expect(returnedUsers).toEqual(orderedUsers.map(serializeUser));
expect(returnedUsers).toEqual(usersSortedByDescendingEmail.map(serializeUser));

const listRequests = await listHandler.requests();
expect(listRequests).toHaveLength(1);
Expand All @@ -420,12 +420,12 @@ async function declareDefaultClientTests(options: ClientTestOptionsByWorkerType)
expect(await listRequests[0].raw.text()).toBe('');

expectTypeOf(listRequests[0].response.body).toEqualTypeOf<JSONSerialized<User>[]>();
expect(listRequests[0].response.body).toEqual(orderedUsers.map(serializeUser));
expect(listRequests[0].response.body).toEqual(usersSortedByDescendingEmail.map(serializeUser));

expectTypeOf(listRequests[0].response.raw).toEqualTypeOf<HttpResponse<JSONSerialized<User>[], 200>>();
expect(listRequests[0].response.raw).toBeInstanceOf(Response);
expectTypeOf(listRequests[0].response.raw.json).toEqualTypeOf<() => Promise<JSONSerialized<User>[]>>();
expect(await listRequests[0].response.raw.json()).toEqual(orderedUsers.map(serializeUser));
expect(await listRequests[0].response.raw.json()).toEqual(usersSortedByDescendingEmail.map(serializeUser));
});
});

Expand Down
2 changes: 1 addition & 1 deletion apps/zimic-test-client/vitest.workspace.mts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default defineWorkspace([
{
extends: 'vitest.config.mts',
test: {
name: 'browser',
name: 'browser-chromium',
environment: undefined,
include: ['./{src,tests}/**/*.test.ts', './{src,tests}/**/*.browser.test.ts'],
exclude: ['**/*.node.test.ts'],
Expand Down
3 changes: 2 additions & 1 deletion examples/with-typegen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"test": "vitest",
"test:turbo": "dotenv -v CI=true -- pnpm run test run",
"types:check": "tsc --noEmit",
"typegen:github": "dotenv -c development -- bash -c 'zimic typegen openapi $GITHUB_OPENAPI_SPEC_URL --output ./src/types/github/typegen/generated.ts --service-name GitHub --filter-file ./src/types/github/typegen/filters.txt --no-comments'"
"typegen:github": "dotenv -c development -- pnpm typegen:github-no-env",
"typegen:github-no-env": "zimic typegen openapi $GITHUB_OPENAPI_SPEC_URL --output ./src/types/github/typegen/generated.ts --service-name GitHub --filter-file ./src/types/github/typegen/filters.txt --no-comments"
},
"dependencies": {
"fastify": "4.28.1",
Expand Down
7 changes: 7 additions & 0 deletions packages/zimic/src/cli/__tests__/server.cli.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@ describe('CLI (server)', async () => {

const processArgvSpy = vi.spyOn(process, 'argv', 'get');
const processOnSpy = vi.spyOn(process, 'on');
const processExitSpy = vi.spyOn(process, 'exit').mockReturnValue(undefined as never);

beforeEach(() => {
processArgvSpy.mockClear();
processArgvSpy.mockReturnValue([]);

processOnSpy.mockClear();
processExitSpy.mockClear();
});

const serverHelpOutput = [
Expand Down Expand Up @@ -299,6 +301,9 @@ describe('CLI (server)', async () => {

const savedFile = await filesystem.readFile(temporarySaveFile, 'utf-8');
expect(savedFile).toBe(temporarySaveFileContent);

expect(processExitSpy).toHaveBeenCalledTimes(1);
expect(processExitSpy).toHaveBeenCalledWith(0);
});
});

Expand Down Expand Up @@ -335,6 +340,8 @@ describe('CLI (server)', async () => {

const savedFile = await filesystem.readFile(temporarySaveFile, 'utf-8');
expect(savedFile).toBe(temporarySaveFileContent);

expect(processExitSpy).not.toHaveBeenCalled();
});
},
);
Expand Down
1 change: 1 addition & 0 deletions packages/zimic/src/cli/server/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ async function startInterceptorServer({

if (ephemeral) {
await server.stop();
process.exit(0);
}
}

Expand Down

0 comments on commit bb2af96

Please sign in to comment.