Skip to content

Commit

Permalink
Merge pull request #18 from embroider-build/mjs-support
Browse files Browse the repository at this point in the history
Enable both CJS and ESM builds
  • Loading branch information
ef4 authored Oct 31, 2023
2 parents 4a5df8a + b4001fd commit bf720b5
Show file tree
Hide file tree
Showing 21 changed files with 768 additions and 389 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
/*.d.ts
/*.js
/*.js.map
/build/
/dist/
/*.log
/typedoc
!.eslintrc.js
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,6 @@ The other two commands delegate to `scenario-tester`:
* `--scenario <name>` — pick only one specific scenario.
* `--outdir <path>` — path to directory, where to emit a derivative project codebase of the scenario.

### ESM Support

If you are writing your scenario-tests in ESM files you can use the provided `scenario-tester-esm` bin to load your files (exactly as described above). We unfortunately couldn't unify the `scenario-tester` and `scenario-tester-esm` because of a [bug in ts-node](https://github.com/TypeStrong/ts-node/issues/1997) that prevented us from adding ESM support as a minor non-breaking change. If this gets fixed upstream we could potentially unify the implementations in a future release.
6 changes: 3 additions & 3 deletions cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import yargs from 'yargs';

yargs
yargs(process.argv.slice(2))
.demandCommand(1, 'Use one of the above commands')
.command(
'list',
Expand All @@ -22,7 +22,7 @@ yargs
.array('require')
.option('matrix', { type: 'string' }),
async argv => {
let mod = await import('./list');
let mod = await import('./list.js');
await mod.printList(argv);
}
)
Expand Down Expand Up @@ -53,7 +53,7 @@ yargs
})
.array('require'),
async argv => {
let mod = await import('./output');
let mod = await import('./output.js');
await mod.output(argv);
}
)
Expand Down
9 changes: 7 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,15 +316,20 @@ export class Scenarios {
}
}

export const seenScenarios: Scenario[] = [];
declare global {
// eslint-disable-next-line no-var
var scenarioTesterSeenScenarios: Scenario[];
}

global.scenarioTesterSeenScenarios = [];

export class Scenario {
constructor(
public name: string,
private callbackCreateProject: CallbackCreateProject,
private mutators: CallbackMutateProject[]
) {
seenScenarios.push(this);
global.scenarioTesterSeenScenarios.push(this);
}

async prepare(outdir?: string): Promise<PreparedApp> {
Expand Down
22 changes: 17 additions & 5 deletions list.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Scenario, seenScenarios } from '.';
import { sync as globSync } from 'glob';
import { Scenario } from './index.js';
import glob from 'glob';
import { resolve } from 'path';
import { format } from 'util';
import { createRequire } from 'node:module';

const { sync: globSync } = glob;

export interface ListParams {
files: string[];
Expand All @@ -12,15 +15,24 @@ export interface ListParams {
export async function list(params: ListParams): Promise<Scenario[]> {
if (params.require) {
for (let r of params.require) {
require(require.resolve(r, { paths: [process.cwd()]}));
if(import.meta.url) {
const require = createRequire(import.meta.url);
await import(require.resolve(r, { paths: [process.cwd()]}));
} else {
require(require.resolve(r, { paths: [process.cwd()]}));
}
}
}
for (let pattern of params.files) {
for (let file of globSync(pattern)) {
require(resolve(file));
if(import.meta.url) {
await import(resolve(file));
} else {
require(resolve(file));
}
}
}
return seenScenarios;
return global.scenarioTesterSeenScenarios;
}

export async function printList(params: ListParams) {
Expand Down
6 changes: 3 additions & 3 deletions output.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { removeSync } from 'fs-extra';
import { list, ListParams } from './list';
import fs from 'fs-extra';
import { list, ListParams } from './list.js';

export interface OutputParams extends ListParams {
scenario: string;
Expand All @@ -11,7 +11,7 @@ export async function output(params: OutputParams) {
for (let scenario of scenarios) {
if (scenario.name.indexOf(params.scenario) !== -1) {
process.stdout.write(`Found scenario ${scenario.name}\n`);
removeSync(params.outdir);
fs.removeSync(params.outdir);
await scenario.prepare(params.outdir);
process.stdout.write(`Wrote successfully to ${params.outdir}\n`);
return;
Expand Down
39 changes: 31 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,28 @@
"repository": "https://github.com/ef4/scenario-tester",
"version": "2.1.2",
"bin": {
"scenario-tester": "./cli.js"
"scenario-tester": "./dist/cli.js",
"scenario-tester-esm": "./dist/cli.mjs"
},
"main": "index.js",
"scripts": {
"prepare": "tsc",
"prepare": "yarn build",
"build": "yarn tsup cli.ts index.ts list.ts output.ts --tsconfig tsconfig.esm.json --dts --format esm,cjs",
"start": "tsc --watch",
"test": "qunit test.js",
"test": "concurrently --no-color \"npm:test:*\" --names \"test:\"",
"test:ts": "node node_modules/.bin/qunit --require ts-node/register tests/test.ts",
"test:cjs": "qunit tests/test.cjs",
"test:esm": "qunit tests/test.mjs",
"docs": "typedoc index.ts --out typedoc/",
"docs:watch": "yarn docs -- --watch",
"docs:serve": "browser-sync start --server \"typedoc/\" --files \"**/*.html\"",
"docs:dev": "concurrently \"yarn docs:watch\" \"yarn docs:serve\"",
"lint": "eslint '*.ts'"
},
"files": [
"*.js",
"*.d.ts",
"*.map",
"!test.*"
"build/*.js",
"build/*.d.ts",
"build/*.map",
"!build/tests/*"
],
"dependencies": {
"fixturify-project": "^6.0.0",
Expand All @@ -35,6 +39,9 @@
"node": "18.17.0",
"yarn": "1.22.18"
},
"resolutions": {
"type-fest": "^3.0.0"
},
"devDependencies": {
"@types/fs-extra": "^9.0.7",
"@types/qunit": "^2.11.3",
Expand All @@ -46,9 +53,25 @@
"concurrently": "^8.2.0",
"eslint": "^8.46.0",
"eslint-plugin-tsdoc": "^0.2.17",
"execa": "^5.0.1",
"lite-server": "^2.6.1",
"qunit": "^2.18.0",
"ts-node": "^10.9.1",
"tsconfig-to-dual-package": "^1.2.0",
"tsup": "^7.2.0",
"typedoc": "^0.24.8",
"typescript": "^5.1.6"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./*": {
"types": "./dist/*.d.ts",
"import": "./dist/*.mjs",
"require": "./dist/*.js"
}
}
}
89 changes: 89 additions & 0 deletions test-modules.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Project } from 'fixturify-project';
import { Scenarios } from './index.js';
import Qunit from 'qunit';
import child_process from 'child_process';

function hello1(project) {
project.linkDependency('hello', {
baseDir: './fixtures',
resolveName: 'hello1',
});
}

function hello2(project) {
project.linkDependency('hello', {
baseDir: './fixtures',
resolveName: 'hello',
});
}

const scenarios = Scenarios.fromDir('./fixtures/app').expand({
hello1,
hello2,
});

scenarios.forEachScenario((scenario) => {
Qunit.module(scenario.name, (hooks) => {
hooks.before(async function ({ app }) {
this.app = await scenario.prepare();
});

Qunit.test(
'yarn test',
async function (assert) {
const result = await this.app.execute('yarn --silent test');
assert.equal(
result.stdout,
`TAP version 13
ok 1 project > createHello
1..1
# pass 1
# skip 0
# todo 0
# fail 0
`
);
}
);

Qunit.test(
'yarn bin inside app',
async function (assert) {
let result = await this.app.execute('yarn --silent bin');
const yarnBin = result.stdout.trimRight();
assert.ok(yarnBin.startsWith(this.app.dir));
result = await this.app.execute('yarn --silent exec which qunit');
assert.ok(result.stdout.startsWith(yarnBin));
}
);

Qunit.test(
'check scenario',
async function (assert) {
let result = await this.app.execute(
`node -p 'require("./index").polyfilled'`
);
assert.equal(
result.stdout.trim(),
('hello1' === scenario.name).toString()
);
}
);
});
});

Qunit.module('cli', () => {
Qunit.test('list', (assert) => {
assert.deepEqual(
child_process
.execFileSync(
process.execPath,
['cli.js', 'list', '--files', 'test-modules.mjs', '--matrix'],
{ encoding: 'utf8' }
)
.trimRight()
.split('\n'),
['hello1', 'hello2']
);
});
});
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
64 changes: 64 additions & 0 deletions tests/test.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"use strict";

const { Scenarios } = require('scenario-tester');
const qunit = require("qunit");
const child_process = require("child_process");
const execa = require('execa');

function hello1(project) {
project.linkDependency('hello', {
baseDir: './tests/fixtures',
resolveName: 'hello1',
});
}
function hello2(project) {
project.linkDependency('hello', {
baseDir: './tests/fixtures',
resolveName: 'hello',
});
}
const scenarios = Scenarios.fromDir('./tests/fixtures/app').expand({
hello1,
hello2,
});
scenarios.forEachScenario((scenario) => {
qunit.module(scenario.name, (hooks) => {
hooks.before(async function () {
this.app = await scenario.prepare();
});
qunit.test('yarn test', async function (assert) {
const result = await this.app.execute('yarn --silent test');
assert.equal(result.stdout, `TAP version 13
ok 1 project > createHello
1..1
# pass 1
# skip 0
# todo 0
# fail 0
`);
});
qunit.test('yarn bin inside app', async function (assert) {
let result = await this.app.execute('yarn --silent bin');
const yarnBin = result.stdout.trimRight();
assert.ok(yarnBin.startsWith(this.app.dir));
result = await this.app.execute('yarn --silent exec which qunit');
assert.ok(result.stdout.startsWith(yarnBin));
});
qunit.test('check scenario', async function (assert) {
let result = await this.app.execute(`node -p 'require("./index").polyfilled'`);
assert.equal(result.stdout.trim(), ('hello1' === scenario.name).toString());
});
});
});
qunit.module('cli', () => {
qunit.test('list', async (assert) => {
const result = await execa('node', ['./dist/cli.js', 'list', '--files', 'tests/test.cjs', '--matrix'])

const { stdout } = result;
assert.deepEqual(
stdout.split('\n'),
['hello1', 'hello2']
);
});
});
//# sourceMappingURL=test.js.map
Loading

0 comments on commit bf720b5

Please sign in to comment.