Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f12f0dc
Add loose/strict flags
Jul 27, 2023
146438d
Add failing test for strict flag
Jul 27, 2023
6aeca69
Add file name mapping for strict flag
Jul 27, 2023
05a4e8e
Add gjs template blueprint
Jul 27, 2023
b1b5b8b
Filter files depending on loose/strict flag
Jul 27, 2023
968a4f9
Add gjs test fixture
Jul 27, 2023
174fa19
fix component import path
Jul 27, 2023
b40058d
Add component-test strict blueprint
Jul 27, 2023
7331d88
filter blueprint files for component-test
Jul 27, 2023
19203ea
Add strict component test test (no typo)
Jul 27, 2023
c75f887
Add component test strict fixture
Jul 27, 2023
8a5fdd9
Use authoringFormat option instead of explicit flags
Jul 27, 2023
5808ca0
Use authoringFormat option instead of flags in component
Jul 27, 2023
cb32d4d
Revert explicit fileMapTokens for strict format
Jul 27, 2023
daaf12e
Only log skippedJsFiles in loose mode
Jul 27, 2023
1b3fbf9
Don't store filteresJsFiles for authoring format
Jul 27, 2023
6ab3dfa
do not log skippedJsFiles in component-test either
Jul 27, 2023
bc17956
fix afterInstall param location
Jul 30, 2023
812e306
Fix blueprint closing tags
Jul 30, 2023
0230202
Remove log
Jul 30, 2023
45980bf
fix: add components to import path
Jul 30, 2023
cf5cc5e
Add yield to template-only gjs
Jul 30, 2023
b8da89b
Make component blueprint ts by default
Jul 30, 2023
0cb80f4
Add js blueprints
Jul 30, 2023
ef12744
Move test to outside of pod
Jul 30, 2023
d6fc532
remove default template test gjs
Jul 30, 2023
9ee888f
check rfc fixture
Jul 30, 2023
5808020
fix: nested component invocation
Jul 30, 2023
f297ea9
remove log
Jul 30, 2023
59085bd
feat: add template tag aliasses
Aug 2, 2023
0c8cd41
chore: rename param to component-authoring-format
Aug 2, 2023
5d1c505
fix: remove assert on test
Oct 17, 2023
4aabf44
Merge branch 'emberjs:main' into template-tag-blueprints
IgnaceMaes Aug 14, 2024
c11d10a
chore: update test doc comments to reflect new test waiter api
IgnaceMaes Aug 14, 2024
879e576
chore: update doc help
IgnaceMaes Aug 14, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<% if (testType === 'integration') { %>import { module, test } from 'qunit';
import { setupRenderingTest } from '<%= modulePrefix %>/tests/helpers';
import { render } from '@ember/test-helpers';
import <%= componentName %> from '<%= modulePrefix %>/components/<%= componentPathName %>';

module('<%= friendlyTestDescription %>', function (hooks) {
setupRenderingTest(hooks);

test('it renders', async function (assert) {
// Updating values is achieved using autotracking, just like in app code. For example:
// class State { @tracked myProperty = 0; }; const state = new State();
// and update using state.myProperty = 1; await rerender();
// Handle any actions with function myAction(val) { ... };

await render(<template><%= selfCloseComponent(componentName) %></template>);

assert.dom().hasText('');

// Template block usage:
await render(<template>
<%= openComponent(componentName) %>
template block text
<%= closeComponent(componentName) %>
</template>);

assert.dom().hasText('template block text');
});
});<% } else if (testType === 'unit') { %>import { module, test } from 'qunit';
import { setupTest } from '<%= modulePrefix %>/tests/helpers';

module('<%= friendlyTestDescription %>', function (hooks) {
setupTest(hooks);

test('it exists', function (assert) {
let component = this.owner.factoryFor('component:<%= componentPathName %>').create();
assert.ok(component);
});
}); <% } %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
{{yield}}
</template>
35 changes: 34 additions & 1 deletion blueprints/component-test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ function invocationFor(options) {
return parts.map((p) => stringUtil.classify(p)).join('::');
}

function invocationForStrictComponentAuthoringFormat(options) {
let parts = options.entity.name.split('/');
let componentName = parts[parts.length - 1];
return stringUtil.classify(componentName);
}

module.exports = useTestFrameworkDetector({
description: 'Generates a component integration or unit test.',

Expand All @@ -37,6 +43,17 @@ module.exports = useTestFrameworkDetector({
{ unit: 'unit' },
],
},
{
name: 'component-authoring-format',
type: ['loose', 'strict'],
default: 'loose',
aliases: [
{ loose: 'loose' },
{ strict: 'strict' },
{ 'template-tag': 'strict' },
{ tt: 'strict' },
],
},
],

fileMapTokens: function () {
Expand All @@ -56,6 +73,19 @@ module.exports = useTestFrameworkDetector({
};
},

files() {
let files = this._super.files.apply(this, arguments);

if (this.options.componentAuthoringFormat === 'strict') {
files = files.filter((file) => !(file.endsWith('.js') || file.endsWith('.ts')));
}
if (this.options.componentAuthoringFormat === 'loose') {
files = files.filter((file) => !(file.endsWith('.gjs') || file.endsWith('.gts')));
}

return files;
},

locals: function (options) {
let dasherizedModuleName = stringUtil.dasherize(options.entity.name);
let componentPathName = dasherizedModuleName;
Expand All @@ -75,7 +105,10 @@ module.exports = useTestFrameworkDetector({
? "import { hbs } from 'ember-cli-htmlbars';"
: "import hbs from 'htmlbars-inline-precompile';";

let templateInvocation = invocationFor(options);
let templateInvocation =
this.options.componentAuthoringFormat === 'strict'
? invocationForStrictComponentAuthoringFormat(options)
: invocationFor(options);
let componentName = templateInvocation;
let openComponent = (descriptor) => `<${descriptor}>`;
let closeComponent = (descriptor) => `</${descriptor}>`;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<% if (testType === 'integration') { %>import { module, test } from 'qunit';
import { setupRenderingTest } from '<%= modulePrefix %>/tests/helpers';
import { render } from '@ember/test-helpers';
import <%= componentName %> from '<%= modulePrefix %>/components/<%= componentPathName %>';

module('<%= friendlyTestDescription %>', function (hooks) {
setupRenderingTest(hooks);

test('it renders', async function (assert) {
// Updating values is achieved using autotracking, just like in app code. For example:
// class State { @tracked myProperty = 0; }; const state = new State();
// and update using state.myProperty = 1; await rerender();
// Handle any actions with function myAction(val) { ... };

await render(<template><%= selfCloseComponent(componentName) %></template>);

assert.dom().hasText('');

// Template block usage:
await render(<template>
<%= openComponent(componentName) %>
template block text
<%= closeComponent(componentName) %>
</template>);

assert.dom().hasText('template block text');
});
});<% } else if (testType === 'unit') { %>import { module, test } from 'qunit';
import { setupTest } from '<%= modulePrefix %>/tests/helpers';

module('<%= friendlyTestDescription %>', function (hooks) {
setupTest(hooks);

test('it exists', function (assert) {
let component = this.owner.factoryFor('component:<%= componentPathName %>').create();
assert.ok(component);
});
}); <% } %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
{{yield}}
</template>
Comment on lines +1 to +3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

35 changes: 28 additions & 7 deletions blueprints/component/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ module.exports = {
default: OCTANE ? 'flat' : 'classic',
aliases: OCTANE ? [{ fs: 'flat' }, { ns: 'nested' }, { cs: 'classic' }] : [{ cs: 'classic' }],
},
{
name: 'component-authoring-format',
type: ['loose', 'strict'],
default: 'loose',
aliases: [
{ loose: 'loose' },
{ strict: 'strict' },
{ 'template-tag': 'strict' },
{ tt: 'strict' },
],
},
],

/**
Expand Down Expand Up @@ -135,14 +146,16 @@ module.exports = {
afterInstall(options) {
this._super.afterInstall.apply(this, arguments);

this.skippedJsFiles.forEach((file) => {
let mapped = this.mapFile(file, this.savedLocals);
this.ui.writeLine(` ${chalk.yellow('skip')} ${mapped}`);
});
if (options.componentAuthoringFormat === 'loose') {
this.skippedJsFiles.forEach((file) => {
let mapped = this.mapFile(file, this.savedLocals);
this.ui.writeLine(` ${chalk.yellow('skip')} ${mapped}`);
});

if (this.skippedJsFiles.size > 0) {
let command = `ember generate component-class ${options.entity.name}`;
this.ui.writeLine(` ${chalk.cyan('tip')} to add a class, run \`${command}\``);
if (this.skippedJsFiles.size > 0) {
let command = `ember generate component-class ${options.entity.name}`;
this.ui.writeLine(` ${chalk.cyan('tip')} to add a class, run \`${command}\``);
}
}
},

Expand Down Expand Up @@ -225,6 +238,14 @@ module.exports = {
}
});
}
if (this.options.componentAuthoringFormat === 'strict') {
files = files.filter(
(file) => !(file.endsWith('.js') || file.endsWith('.ts') || file.endsWith('.hbs'))
);
}
if (this.options.componentAuthoringFormat === 'loose') {
files = files.filter((file) => !(file.endsWith('.gjs') || file.endsWith('.gts')));
}

return files;
},
Expand Down
8 changes: 8 additions & 0 deletions node-tests/blueprints/component-test-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ describe('Blueprint: component-test', function () {
);
});
});

it('component-test x-foo --strict', function () {
return emberGenerateDestroy(['component-test', 'x-foo', '--strict'], (_file) => {
expect(_file('tests/integration/components/x-foo-test.gjs')).to.equal(
fixture('component-test/rfc232.gjs')
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fails when running the TypeScript blueprint tests:

  1) Blueprint: component-test
       in app
         with default setup
           component-test x-foo --strict:
     AssertionError: expected "tests/integration/components/x-foo-test.gjs" to exist

parent path "tests/integration/components" exists and contains:
- x-foo-test.gts
      at /.../ember.js/node-tests/blueprints/component-test-test.js:44:75
      at /.../ember.js/node_modules/.pnpm/[email protected]/node_modules/ember-cli-blueprint-test-helpers/lib/ember-generate-destroy.js:34:17
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

I'm not sure what the next step is here. The other tests don't check on TypeScript-specific files. Is the expect assumed to automatically work for TS too, but it doesn't here?

Welcoming any input 😄

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validating the path dynamically would work:

const filePath = fs.existsSync('tests/integration/components/x-foo-test.gts')
  ? 'tests/integration/components/x-foo-test.gts'
  : 'tests/integration/components/x-foo-test.gjs';

But that seems like logic which shouldn't be in the test.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're getting TypeScript output when the TypeScript blueprints should be converted to JS by the blueprint system (unless it is a typescript project).

I believe this https://github.com/ember-polyfills/ember-cli-typescript-blueprint-polyfill/blob/main/src/utils.js#L13-L15 needs to include gts, but there may be other changes needed for the blueprint system to convert gts to gjs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping @IgnaceMaes on ^

I'd love for this to land in 5.x

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can try to find some time to push this over the finish line as well 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be much appreciated. Realistically, I won't have time to look into this in the near future :/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that was confusing.. 😄

I updated the polyfill and used the branch here, but that still didn't work because the polyfill disables itself if it thinks it's no longer needed. It seems we are depending on ember-cli 4.10 which does support .ts -> .js in the blueprints, but not .gts -> .gjs (which was released in 5.5 I think). Once I bump the version to 5.12 the test no longer seems to fail.

What was extra confusing is that there are no tests that verify the .ts version of the blueprints: #20362

);
});
});
});

describe('with [email protected]', function () {
Expand Down
11 changes: 11 additions & 0 deletions node-tests/blueprints/component-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ const templateOnlyContents = `import templateOnly from '@ember/component/templat
export default templateOnly();
`;

const templateTagContents = `<template>
{{yield}}
</template>
`;

describe('Blueprint: component', function () {
setupTestHooks(this);

Expand Down Expand Up @@ -324,6 +329,12 @@ describe('Blueprint: component', function () {
);
});

it('component foo --strict', function () {
return emberGenerateDestroy(['component', 'foo', '--strict'], (_file) => {
expect(_file('app/components/foo.gjs')).to.equal(templateTagContents);
});
});

describe('with podModulePrefix', function () {
beforeEach(function () {
setupPodConfig({ podModulePrefix: true });
Expand Down
28 changes: 28 additions & 0 deletions node-tests/fixtures/component-test/rfc232.gjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'my-app/tests/helpers';
import { render } from '@ember/test-helpers';
import XFoo from 'my-app/components/x-foo';

module('Integration | Component | x-foo', function (hooks) {
setupRenderingTest(hooks);

test('it renders', async function (assert) {
// Updating values is achieved using autotracking, just like in app code. For example:
// class State { @tracked myProperty = 0; }; const state = new State();
// and update using state.myProperty = 1; await rerender();
// Handle any actions with function myAction(val) { ... };

await render(<template><XFoo /></template>);

assert.dom().hasText('');

// Template block usage:
await render(<template>
<XFoo>
template block text
</XFoo>
</template>);

assert.dom().hasText('template block text');
});
});