Skip to content

Commit

Permalink
Merge pull request #156 from embroider-build/component-compilation-tests
Browse files Browse the repository at this point in the history
Component compilation tests
  • Loading branch information
NullVoxPopuli authored Jul 17, 2023
2 parents 35e7ca0 + 000049a commit 85981bd
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 53 deletions.
6 changes: 6 additions & 0 deletions tests/fixtures/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
This way of doing fixtures allows us to set up multiple scenarios for different inputs to our tests.

```
./fixtures/${scenarioName}/ ... files and folders for the scenario ...
```

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello, {{this.whereAmI}}
5 changes: 5 additions & 0 deletions tests/fixtures/default/my-addon/src/components/co-located.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Component from '@glimmer/component';

export default class CoLocated extends Component {
whereAmI = 'from a co-located component';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello from a template-only component
14 changes: 14 additions & 0 deletions tests/fixtures/default/test-app/tests/rendering/co-located-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';

module('Rendering | co-located', function(hooks) {
setupRenderingTest(hooks);

test('it renders', async function(assert) {
await render(hbs`<CoLocated />`);

assert.dom().hasText('Hello, from a co-located component');
})
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';

module('Rendering | template-only', function(hooks) {
setupRenderingTest(hooks);

test('it renders', async function(assert) {
await render(hbs`<TemplateOnly />`);

assert.dom().hasText('Hello from a template-only component');
})
});
24 changes: 24 additions & 0 deletions tests/helpers/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,32 @@ export async function copyFixture(
newFile = path.join(options.cwd, newFile);
}

let fullFixturePath = path.join(fixturesPath, scenario, fixtureFile);
let exists = await fse.pathExists(fullFixturePath);

assert(
exists,
`Fixture path '${fixtureFile}' does not exist. To make this work, place a new file/folder '${fixtureFile}' in the 'tests/fixtures/${scenario}' directory. Checked the absolute path: '${fullFixturePath}'.`
);

if (await isDirectory(fullFixturePath)) {
await fse.copy(fullFixturePath, newFile);

return;
}

let fixtureContents = await readFixture(fixtureFile, { scenario });

await fse.mkdir(path.dirname(newFile), { recursive: true });
await fs.writeFile(newFile, fixtureContents);
}

async function isDirectory(maybePath: string) {
try {
const stats = await fs.stat(maybePath);

return stats.isDirectory();
} catch {
return false;
}
}
46 changes: 36 additions & 10 deletions tests/helpers/meta-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ const DEBUG = process.env.DEBUG === 'true';
*
*/
export class AddonHelper {
#cwd?: string;
#projectRoot?: string;
#tmpDir?: string;
#scenario: string;
#packageManager: 'npm' | 'pnpm' | 'yarn';
#addonFolder?: string;
#args: string[];
#fixtures: AddonFixtureHelper | undefined;

Expand All @@ -45,20 +46,33 @@ export class AddonHelper {
console.debug(`Debug test repo at ${this.#tmpDir}`);
}

let args = [...this.#args];
let needsPackageManagerSet =
!args.includes(`--${this.#packageManager}`) &&
!args.some((arg) => arg.startsWith('--packageManager')) &&
!args.some((arg) => arg.startsWith('--npm')) &&
!args.some((arg) => arg.startsWith('--yarn')) &&
!args.some((arg) => arg.startsWith('--pnpm'));

if (needsPackageManagerSet) {
args.push(`--${this.#packageManager}`);
}

let { name } = await createAddon({
args: this.#args,
args,
options: { cwd: this.#tmpDir },
});

// this is the project root
this.#cwd = path.join(this.#tmpDir, name);
this.#projectRoot = path.join(this.#tmpDir, name);
this.#addonFolder = path.join(this.#projectRoot, name);

this.#fixtures = new AddonFixtureHelper({ cwd: this.#cwd, scenario: this.#scenario });
this.#fixtures = new AddonFixtureHelper({ cwd: this.#projectRoot, scenario: this.#scenario });
}

async run(scriptName: string) {
return await runScript({
cwd: this.cwd,
cwd: this.projectRoot,
script: scriptName,
packageManager: this.#packageManager,
});
Expand All @@ -79,21 +93,33 @@ export class AddonHelper {
await fs.rm(this.#tmpDir, { recursive: true, force: true });
}

async installDeps() {
await install({ cwd: this.cwd, packageManager: this.#packageManager, skipPrepare: true });
async installDeps(options?: { skipPrepare: boolean }) {
let skipPrepare = options?.skipPrepare ?? true;

await install({
cwd: this.projectRoot,
packageManager: this.#packageManager,
skipPrepare,
});
}

get cwd() {
assert(this.#cwd, "Cannot get cwd. Was the Addon Helper's `setup` method called?");
get projectRoot() {
assert(this.#projectRoot, "Cannot get cwd. Was the Addon Helper's `setup` method called?");

return this.#cwd;
return this.#projectRoot;
}

get fixtures() {
assert(this.#fixtures, 'Cannot get fixtures-helper. Was the Addon Helper `setup`?');

return this.#fixtures;
}

get addonFolder() {
assert(this.#addonFolder, 'Cannot get addon folder. Was the Addon Helper `setup`?');

return this.#addonFolder;
}
}

export class AddonFixtureHelper {
Expand Down
18 changes: 13 additions & 5 deletions tests/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const DEBUG = process.env.DEBUG === 'true';
const __dirname = path.dirname(fileURLToPath(import.meta.url));

// repo-root
Expand Down Expand Up @@ -128,11 +129,18 @@ export async function createAddon({
args?: string[];
options?: Options;
}) {
let result = await execa(
'ember',
['addon', name, '-b', blueprintPath, '--skip-npm', '--skip-git', ...args],
{ ...options, env: { ...options.env, EMBER_CLI_PNPM: 'true' }, preferLocal: true }
);
let emberCliArgs = ['addon', name, '-b', blueprintPath, '--skip-npm', '--skip-git', ...args];

if (DEBUG) {
console.debug(`Running ember-cli in ${options.cwd}`);
console.debug(`\tember ${emberCliArgs.join(' ')}`);
}

let result = await execa('ember', emberCliArgs, {
...options,
env: { ...options.env, EMBER_CLI_PNPM: 'true' },
preferLocal: true,
});

// Light work-around for an upstream `@babel/core` peer issue
if (typeof options.cwd === 'string') {
Expand Down
6 changes: 4 additions & 2 deletions tests/smoke-tests/--addon-only.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ describe('--addon-only', () => {
});

it('is not a monorepo', async () => {
let hasPnpmWorkspace = await fse.pathExists(path.join(helper.cwd, 'pnpm-workspace.yaml'));
let packageJson = await fse.readJson(path.join(helper.cwd, 'package.json'));
let hasPnpmWorkspace = await fse.pathExists(
path.join(helper.projectRoot, 'pnpm-workspace.yaml')
);
let packageJson = await fse.readJson(path.join(helper.projectRoot, 'package.json'));

expect(hasPnpmWorkspace).toBe(false);
// Pnpm doesn't use this field, but it's good that it doesn't exist.
Expand Down
67 changes: 31 additions & 36 deletions tests/smoke-tests/defaults.test.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,34 @@
import fse from 'fs-extra';
import fs from 'node:fs/promises';
import path from 'node:path';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';

import {
AddonHelper,
assertGeneratedCorrectly,
createAddon,
createTmp,
dirContents,
install,
runScript,
SUPPORTED_PACKAGE_MANAGERS,
} from '../helpers.js';

for (let packageManager of SUPPORTED_PACKAGE_MANAGERS) {
describe(`defaults with ${packageManager}`, () => {
let cwd = '';
let tmpDir = '';
let distDir = '';
let helper = new AddonHelper({ packageManager });

beforeAll(async () => {
tmpDir = await createTmp();
await helper.setup();
await helper.installDeps({ skipPrepare: false });

console.debug(`Debug test repo at ${tmpDir}`);

let { name } = await createAddon({
args: [`--${packageManager}=true`],
options: { cwd: tmpDir },
});

cwd = path.join(tmpDir, name);
distDir = path.join(cwd, name, 'dist');

await install({ cwd, packageManager });
distDir = path.join(helper.addonFolder, 'dist');
});

afterAll(async () => {
fs.rm(tmpDir, { recursive: true, force: true });
await helper.clean();
});

it('is using the correct packager', async () => {
let npm = path.join(cwd, 'package-lock.json');
let yarn = path.join(cwd, 'yarn.lock');
let pnpm = path.join(cwd, 'pnpm-lock.yaml');
let npm = path.join(helper.projectRoot, 'package-lock.json');
let yarn = path.join(helper.projectRoot, 'yarn.lock');
let pnpm = path.join(helper.projectRoot, 'pnpm-lock.yaml');

switch (packageManager) {
case 'npm': {
Expand Down Expand Up @@ -79,29 +65,38 @@ for (let packageManager of SUPPORTED_PACKAGE_MANAGERS) {
});

it('was generated correctly', async () => {
assertGeneratedCorrectly({ projectRoot: cwd });
assertGeneratedCorrectly({ projectRoot: helper.projectRoot });
});

it('builds the addon', async () => {
let { exitCode } = await runScript({ cwd, script: 'build', packageManager });
// Tests are additive, so when running them in order, we want to check linting
// before we add files from fixtures
it('lints all pass', async () => {
let { exitCode } = await helper.run('lint');

expect(exitCode).toEqual(0);
});

let contents = await dirContents(distDir);
it('build and test ', async () => {
// Copy over fixtures
await helper.fixtures.use('./my-addon/src/components');
await helper.fixtures.use('./test-app/tests');
// Sync fixture with project's lint / formatting configuration
await helper.run('lint:fix');

expect(contents).to.deep.equal(['index.js', 'index.js.map']);
});
let buildResult = await helper.build();

it('runs tests', async () => {
let { exitCode } = await runScript({ cwd, script: 'test', packageManager });
expect(buildResult.exitCode).toEqual(0);

expect(exitCode).toEqual(0);
});
let contents = await dirContents(distDir);

it('lints all pass', async () => {
let { exitCode } = await runScript({ cwd, script: 'lint', packageManager });
expect(contents).to.deep.equal(['_app_', 'components', 'index.js', 'index.js.map']);

expect(exitCode).toEqual(0);
let testResult = await helper.run('test');

expect(testResult.exitCode).toEqual(0);
expect(testResult.stdout).to.include('# tests 3');
expect(testResult.stdout).to.include('# pass 3');
expect(testResult.stdout).to.include('# fail 0');
});
});
}

0 comments on commit 85981bd

Please sign in to comment.