Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: setup jest in Stimulus variants #465

Merged
merged 5 commits into from
Aug 14, 2023
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

This file was deleted.

1 change: 1 addition & 0 deletions variants/frontend-react-typescript/babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const config = api => {
]
].filter(notFalseGuard),
plugins: [
['@babel/plugin-transform-typescript', { allowDeclareFields: true }],
isProductionEnv && [
'babel-plugin-transform-react-remove-prop-types',
{
Expand Down
13 changes: 2 additions & 11 deletions variants/frontend-react-typescript/template.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
source_paths.unshift(File.dirname(__FILE__))

installed_jest_major_version = JSON.parse(File.read("node_modules/jest/package.json")).fetch("version").split(".").first

run "yarn remove prop-types"
yarn_add_dependencies %w[@types/react @types/react-dom]
yarn_add_dev_dependencies [
"@types/jest@#{installed_jest_major_version}",
"@jest/types@#{installed_jest_major_version}",
"ts-jest@#{installed_jest_major_version}",
"ts-node"
]
run "yarn install"

rename_js_file_to_ts "app/frontend/packs/server_rendering"

Expand Down Expand Up @@ -50,5 +41,5 @@
TYPES
end

remove_dir "app/frontend/test"
directory "app/frontend/test"
remove_dir "app/frontend/test/components"
directory "app/frontend/test/components"
2 changes: 1 addition & 1 deletion variants/frontend-react/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const config = {
env: { commonjs: true, node: true, browser: true },
extends: ['ackama', 'ackama/react'],
ignorePatterns: ['tmp/'],
parserOptions: { sourceType: 'module' },
parserOptions: { sourceType: 'module', ecmaVersion: 2022 },
overrides: [
{
files: [
Expand Down
49 changes: 14 additions & 35 deletions variants/frontend-react/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@

run "rails generate react:install"

# @testing-library/react brings in @testing-library/dom as a direct dependency,
# and so should be favored when importing as it is the more specific package
run "yarn remove @testing-library/dom"

gsub_file "app/frontend/test/stimulus/controllers/add_class_controller.test.js",
"'@testing-library/dom'",
"'@testing-library/react'"

yarn_add_dependencies %w[
@babel/preset-react
babel-plugin-transform-react-remove-prop-types
Expand All @@ -15,23 +23,11 @@
prop-types
]

# We need the major version of the 'jest', '@jest/types', 'ts-jest' packages to
# match so we can only upgrade jest when there are compatible versions available
jest_major_version = "29"

yarn_add_dev_dependencies [
"@testing-library/react",
"@testing-library/jest-dom",
"@testing-library/user-event",
"eslint-plugin-react",
"eslint-plugin-react-hooks",
"eslint-plugin-jsx-a11y",
"eslint-plugin-jest",
"eslint-plugin-jest-formatting",
"eslint-plugin-jest-dom",
"eslint-plugin-testing-library",
"jest-environment-jsdom",
"jest@#{jest_major_version}"
yarn_add_dev_dependencies %w[
@testing-library/react
eslint-plugin-react
eslint-plugin-react-hooks
eslint-plugin-jsx-a11y
]
copy_file ".eslintrc.js", force: true
copy_file "babel.config.js", force: true
Expand Down Expand Up @@ -76,9 +72,7 @@

# example file
copy_file "app/frontend/components/HelloWorld.jsx", force: true

# test files
directory "app/frontend/test"
copy_file "app/frontend/test/components/HelloWorld.spec.jsx", force: true

append_to_file "app/views/home/index.html.erb" do
<<~ERB
Expand All @@ -87,23 +81,8 @@
end

package_json = JSON.parse(File.read("./package.json"))
package_json["scripts"] = package_json["scripts"].merge(
{
"test" => "jest",
"watch-tests" => "jest --watch"
}
)

# we've replaced this with a babel.config.js
package_json.delete "babel"

File.write("./package.json", JSON.generate(package_json))

append_to_file "bin/ci-run" do
<<~JEST
echo "* ******************************************************"
echo "* Running JS tests"
echo "* ******************************************************"
yarn run test --coverage
JEST
end
41 changes: 41 additions & 0 deletions variants/frontend-stimulus-typescript/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

/** @type {import('eslint').Linter.Config} */
const config = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
ecmaVersion: 2019,
lukeify marked this conversation as resolved.
Show resolved Hide resolved
sourceType: 'module'
},
env: { commonjs: true, node: true, browser: true },
extends: ['ackama', 'ackama/@typescript-eslint'],
ignorePatterns: ['tmp/'],
overrides: [
{
files: ['config/webpack/*', 'babel.config.js', '.eslintrc.js'],
parserOptions: { sourceType: 'script' },
rules: {
'@typescript-eslint/prefer-nullish-coalescing': 'off',
'@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/no-var-requires': 'off'
}
},
{
files: ['app/frontend/test/**'],
extends: [
'ackama/jest',
'plugin:jest-dom/recommended',
'plugin:testing-library/dom'
],
plugins: ['testing-library', 'jest-dom'],
rules: {
'jest/prefer-expect-assertions': 'off'
}
}
],
rules: {}
};

module.exports = config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Controller } from '@hotwired/stimulus';

/**
* This controller adds a CSS class to an element or elements when the action is triggered.
* It is intentionally very generic, and doesn't prescribe what event should occur for the
* action to be triggered. Instead, add a `data-action` attribute to your element to determine
* when to add the class. The class name can be specified with `data-add-class-class-name-value`.
*
* See the tests for usage examples.
*/
export default class AddClassController extends Controller<HTMLElement> {
private declare readonly classNameValue: string;
private declare readonly classRecipientTargets: HTMLElement[];

public static values = { className: String };
public static targets = ['classRecipient'];

public add(): void {
for (const target of this.classRecipientTargets) {
target.classList.add(this.classNameValue);
}
}
}
17 changes: 17 additions & 0 deletions variants/frontend-stimulus-typescript/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

const defaultConfigFunc = require('shakapacker/package/babel/preset.js');

/** @type {import('@babel/core').ConfigFunction} */
const config = api => {
const resultConfig = defaultConfigFunc(api);

resultConfig.plugins = [
...resultConfig.plugins,
['@babel/plugin-transform-typescript', { allowDeclareFields: true }]
];

return resultConfig;
};

module.exports = config;
29 changes: 29 additions & 0 deletions variants/frontend-stimulus-typescript/template.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,33 @@
source_paths.unshift(File.dirname(__FILE__))

installed_jest_major_version = JSON.parse(File.read("node_modules/jest/package.json")).fetch("version").split(".").first

yarn_add_dev_dependencies [
"@types/jest@#{installed_jest_major_version}",
"@jest/types@#{installed_jest_major_version}",
"ts-jest@#{installed_jest_major_version}",
"ts-node"
]

copy_file ".eslintrc.js", force: true

remove_file "jest.config.js", force: true
copy_file "jest.config.ts"

copy_file "babel.config.js", force: true

package_json = JSON.parse(File.read("./package.json"))

# we've replaced this with a babel.config.js
package_json.delete "babel"

File.write("./package.json", JSON.generate(package_json))

remove_file "app/frontend/stimulus/controllers/hello_controller.js", force: true
copy_file "app/frontend/stimulus/controllers/hello_controller.ts"

remove_file "app/frontend/stimulus/controllers/add_class_controller.js", force: true
copy_file "app/frontend/stimulus/controllers/add_class_controller.ts"

rename_js_file_to_ts "app/frontend/test/setupExpectEachTestHasAssertions"
rename_js_file_to_ts "app/frontend/test/stimulus/controllers/add_class_controller.test"
29 changes: 29 additions & 0 deletions variants/frontend-stimulus/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

const config = {
root: true,
env: { commonjs: true, node: true, browser: true },
extends: ['ackama'],
ignorePatterns: ['tmp/'],
parserOptions: { sourceType: 'module', ecmaVersion: 2022 },
overrides: [
{
files: ['.eslintrc.js'],
parserOptions: { sourceType: 'script' }
},
{
files: ['app/frontend/test/**'],
extends: [
'ackama/jest',
'plugin:jest-dom/recommended',
'plugin:testing-library/dom'
],
plugins: ['testing-library', 'jest-dom'],
rules: {
'jest/prefer-expect-assertions': 'off'
}
}
]
};

module.exports = config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Controller } from '@hotwired/stimulus';

/**
* This controller adds a CSS class to an element or elements when the action is triggered.
* It is intentionally very generic, and doesn't prescribe what event should occur for the
* action to be triggered. Instead, add a `data-action` attribute to your element to determine
* when to add the class. The class name can be specified with `data-add-class-class-name-value`.
*
* See the tests for usage examples.
*/
export default class AddClassController extends Controller {
static values = { className: String };
static targets = ['classRecipient'];

add() {
for (const target of this.classRecipientTargets) {
target.classList.add(this.classNameValue);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Application } from '@hotwired/stimulus';
import { screen } from '@testing-library/dom';
import userEvent from '@testing-library/user-event';
import AddClassController from '../../../stimulus/controllers/add_class_controller';

const testHTML = `
<div data-controller="add-class" data-add-class-class-name-value="test-class">
<button data-action="add-class#add">Click to add class!</button>
<div data-add-class-target="classRecipient">div one</div>
<div data-add-class-target="classRecipient">div two</div>
</div>
`;

describe('AddClassController', () => {
beforeEach(() => {
document.body.innerHTML = testHTML;

const application = Application.start();

application.register('add-class', AddClassController);
});

it('adds the classes to the target elements when the action is triggered', async () => {
const user = userEvent.setup();

await user.click(screen.getByRole('button'));

expect(screen.getByText('div one')).toHaveClass('test-class');
expect(screen.getByText('div two')).toHaveClass('test-class');
});
});
41 changes: 40 additions & 1 deletion variants/frontend-stimulus/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
@hotwired/stimulus-webpack-helpers
]

copy_file "app/frontend/stimulus/controllers/hello_controller.js"
directory "app/frontend/stimulus/controllers"
directory "app/frontend/test"

prepend_to_file "app/frontend/packs/application.js" do
<<~EO_JS_IMPORTS
Expand Down Expand Up @@ -44,3 +45,41 @@
// window.Stimulus = application;
EO_JS_SETUP
end

# We need the major version of the 'jest', '@jest/types', 'ts-jest' packages to
# match so we can only upgrade jest when there are compatible versions available
jest_major_version = "29"

yarn_add_dev_dependencies %W[
@testing-library/dom
@testing-library/jest-dom
@testing-library/user-event
eslint-plugin-jest
eslint-plugin-jest-formatting
eslint-plugin-jest-dom
eslint-plugin-testing-library
jest-environment-jsdom
jest@#{jest_major_version}
]

copy_file ".eslintrc.js", force: true
copy_file "jest.config.js"

package_json = JSON.parse(File.read("./package.json"))
package_json["scripts"] = package_json["scripts"].merge(
{
"test" => "jest",
"watch-tests" => "jest --watch"
}
)

File.write("./package.json", JSON.generate(package_json))

append_to_file "bin/ci-run" do
<<~JEST
echo "* ******************************************************"
echo "* Running JS tests"
echo "* ******************************************************"
yarn run test --coverage
JEST
end
Loading