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
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ jobs:
run: pnpm test:run

- name: Run build
run: pnpm build
run: pnpm build

- name: Run build smoke tests
run: pnpm test:smoke
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"require": "./dist/index.js",
"import": "./dist/index.mjs",
"types": "./dist/index.d.ts"
"import": "./dist/index.mjs"
}
},
"files": [
Expand All @@ -22,6 +22,7 @@
"build": "tsup",
"test": "vitest",
"test:run": "vitest run",
"test:smoke": "node tests/smoke/esm.smoke.mjs && node tests/smoke/cjs.smoke.cjs && tsc -p tsconfig.smoke.json",
"lint": "eslint .",
"format": "prettier --write .",
"typecheck": "tsc --noEmit",
Expand Down
50 changes: 50 additions & 0 deletions tests/smoke/cjs.smoke.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Verifies that the built package can be consumed via CommonJS `require()`,
// exactly as a downstream consumer would via the "require" condition in
// package.json#exports. Run after `pnpm build` (requires dist/index.js).
const assert = require('node:assert/strict');
const {
GuildPassClient,
GuildPassError,
GuildPassErrorCode,
normaliseAddress,
validateAddress,
formatIsoDate,
DEFAULT_CONFIG,
SUPPORTED_NETWORKS,
} = require('../../dist/index.js');

function expectExport(name, value, expectedType) {
if (typeof value !== expectedType) {
throw new Error(
`[smoke:cjs] Expected "${name}" to be exported as a ${expectedType} from dist/index.js, ` +
`got ${typeof value}. Check src/index.ts and tsup.config.ts for a missing or misconfigured export.`,
);
}
}

expectExport('GuildPassClient', GuildPassClient, 'function');
expectExport('GuildPassError', GuildPassError, 'function');
expectExport('GuildPassErrorCode', GuildPassErrorCode, 'object');
expectExport('normaliseAddress', normaliseAddress, 'function');
expectExport('validateAddress', validateAddress, 'function');
expectExport('formatIsoDate', formatIsoDate, 'function');
expectExport('DEFAULT_CONFIG', DEFAULT_CONFIG, 'object');
expectExport('SUPPORTED_NETWORKS', SUPPORTED_NETWORKS, 'object');

const client = new GuildPassClient({ apiUrl: 'https://smoke-test.invalid' });
assert.equal(client.getConfig().apiUrl, 'https://smoke-test.invalid');
assert.ok(client.access, 'client.access should be initialised');
assert.ok(client.membership, 'client.membership should be initialised');
assert.ok(client.roles, 'client.roles should be initialised');
assert.ok(client.guilds, 'client.guilds should be initialised');
assert.ok(client.contracts, 'client.contracts should be initialised');
assert.equal(GuildPassErrorCode.NOT_FOUND, 'NOT_FOUND');

const error = GuildPassError.fromHttpError(404);
assert.ok(
error instanceof GuildPassError,
'GuildPassError.fromHttpError should return a GuildPassError',
);
assert.equal(error.code, GuildPassErrorCode.NOT_FOUND);

console.log('[smoke:cjs] dist/index.js exports resolved and behave as expected.');
50 changes: 50 additions & 0 deletions tests/smoke/esm.smoke.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Verifies that the built package can be consumed via a native ESM `import`,
// exactly as a downstream consumer would via the "import" condition in
// package.json#exports. Run after `pnpm build` (requires dist/index.mjs).
import assert from 'node:assert/strict';
import {
GuildPassClient,
GuildPassError,
GuildPassErrorCode,
normaliseAddress,
validateAddress,
formatIsoDate,
DEFAULT_CONFIG,
SUPPORTED_NETWORKS,
} from '../../dist/index.mjs';

function expectExport(name, value, expectedType) {
if (typeof value !== expectedType) {
throw new Error(
`[smoke:esm] Expected "${name}" to be exported as a ${expectedType} from dist/index.mjs, ` +
`got ${typeof value}. Check src/index.ts and tsup.config.ts for a missing or misconfigured export.`,
);
}
}

expectExport('GuildPassClient', GuildPassClient, 'function');
expectExport('GuildPassError', GuildPassError, 'function');
expectExport('GuildPassErrorCode', GuildPassErrorCode, 'object');
expectExport('normaliseAddress', normaliseAddress, 'function');
expectExport('validateAddress', validateAddress, 'function');
expectExport('formatIsoDate', formatIsoDate, 'function');
expectExport('DEFAULT_CONFIG', DEFAULT_CONFIG, 'object');
expectExport('SUPPORTED_NETWORKS', SUPPORTED_NETWORKS, 'object');

const client = new GuildPassClient({ apiUrl: 'https://smoke-test.invalid' });
assert.equal(client.getConfig().apiUrl, 'https://smoke-test.invalid');
assert.ok(client.access, 'client.access should be initialised');
assert.ok(client.membership, 'client.membership should be initialised');
assert.ok(client.roles, 'client.roles should be initialised');
assert.ok(client.guilds, 'client.guilds should be initialised');
assert.ok(client.contracts, 'client.contracts should be initialised');
assert.equal(GuildPassErrorCode.NOT_FOUND, 'NOT_FOUND');

const error = GuildPassError.fromHttpError(404);
assert.ok(
error instanceof GuildPassError,
'GuildPassError.fromHttpError should return a GuildPassError',
);
assert.equal(error.code, GuildPassErrorCode.NOT_FOUND);

console.log('[smoke:esm] dist/index.mjs exports resolved and behave as expected.');
27 changes: 27 additions & 0 deletions tests/smoke/types.smoke.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Compile-only check (no emit) that the published declaration file resolves
// the way a downstream consumer would import it via package.json#types
// (dist/index.d.ts). This file is never executed; `tsc -p tsconfig.smoke.json`
// failing to compile it is the signal that the published types are broken.
import {
GuildPassClient,
GuildPassError,
GuildPassErrorCode,
type GuildPassClientConfig,
type NetworkConfig,
} from '../../dist/index';

const config: GuildPassClientConfig = {
apiUrl: 'https://smoke-test.invalid',
};

const client: GuildPassClient = new GuildPassClient(config);
const code: GuildPassErrorCode = GuildPassErrorCode.NOT_FOUND;
const error: GuildPassError = new GuildPassError('smoke test', code);
const network: NetworkConfig = {
chainId: 1,
name: 'smoke-network',
};

void client;
void error;
void network;
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
}
},
"include": ["src/**/*", "tests/**/*", "examples/**/*"],
"exclude": ["node_modules", "dist"]
"exclude": ["node_modules", "dist", "tests/smoke"]
}
11 changes: 11 additions & 0 deletions tsconfig.smoke.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"paths": {},
"skipLibCheck": false
},
"files": ["tests/smoke/types.smoke.ts"]
}
Loading