Skip to content

Commit 226d053

Browse files
Unit Test Support example
1 parent 68fa25c commit 226d053

36 files changed

+649
-0
lines changed

unit-test/.gitignore

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
20+
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*

unit-test/README.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Rsbuild / Create React App Example
2+
3+
This example demos a basic host application loading remote component.
4+
5+
- `host` is the host application (unit_test-based).
6+
- `remote` standalone application (unit_test-based) which exposes `Button` component.
7+
8+
# Running Demo
9+
10+
Run `pnpm run start`. This will build and serve both `host` and `remote` on ports 3001 and 3002 respectively.
11+
12+
- [localhost:3001](http://localhost:3000/) (HOST)
13+
- [localhost:3002](http://localhost:3002/) (STANDALONE REMOTE)
14+
15+
# Running Cypress E2E Tests
16+
17+
To run tests in interactive mode, run `npm run cypress:debug` from the root directory of the project. It will open Cypress Test Runner and allow to run tests in interactive mode. [More info about "How to run tests"](../../cypress/README.md#how-to-run-tests)
18+
19+
To build app and run test in headless mode, run `yarn e2e:ci`. It will build app and run tests for this workspace in headless mode. If tets failed cypress will create `cypress` directory in sample root folder with screenshots and videos.
20+
21+
["Best Practices, Rules amd more interesting information here](../../cypress/README.md)

unit-test/cypress.env.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"allure": true,
3+
"allureResultsPath": "../cypress-e2e/results/allure-results"
4+
}

unit-test/e2e/checkCraApps.cy.ts

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { baseSelectors } from './../../cypress-e2e/common/selectors';
2+
import { BaseMethods } from '../../cypress-e2e/common/base';
3+
import { Constants } from '../../cypress-e2e/fixtures/constants';
4+
5+
const basePage: BaseMethods = new BaseMethods();
6+
7+
const appsData = [
8+
{
9+
appNameText: Constants.commonConstantsData.basicComponents.host,
10+
host: 3000,
11+
},
12+
{
13+
appNameText: Constants.commonConstantsData.basicComponents.remote,
14+
host: 3002,
15+
},
16+
];
17+
18+
appsData.forEach((property: { appNameText: string; host: number }) => {
19+
const appName = property.host === 3000 ? appsData[0].appNameText : appsData[1].appNameText;
20+
21+
describe('CRA', () => {
22+
context(`Check ${appName}`, () => {
23+
beforeEach(() => {
24+
basePage.openLocalhost({
25+
number: property.host,
26+
});
27+
});
28+
29+
it(`Check ${appName} elements exist on the page`, () => {
30+
basePage.checkElementWithTextPresence({
31+
selector: baseSelectors.tags.headers.h1,
32+
text: Constants.commonConstantsData.basicComponents.basicHostRemote,
33+
});
34+
basePage.checkElementWithTextPresence({
35+
selector: baseSelectors.tags.headers.h2,
36+
text: property.appNameText,
37+
});
38+
basePage.checkElementWithTextPresence({
39+
selector: baseSelectors.tags.coreElements.button,
40+
text: Constants.elementsText.craApp.buttonText,
41+
});
42+
});
43+
});
44+
});
45+
});

unit-test/host/.babelrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["@babel/preset-env", "@babel/preset-react"]
3+
}

unit-test/host/.gitignore

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
20+
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*

unit-test/host/__tests__/app.test.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import '@testing-library/jest-dom/extend-expect';
4+
import App from '@src/App.js';
5+
6+
describe('App Component', () => {
7+
beforeAll(async ()=>{
8+
await require('federation-test')
9+
});
10+
test('renders the main heading', () => {
11+
render(<App />);
12+
const mainHeading = screen.getByTestId('main-heading');
13+
expect(mainHeading).toBeInTheDocument();
14+
});
15+
16+
test('renders the subheading', () => {
17+
render(<App />);
18+
const subHeading = screen.getByTestId('sub-heading');
19+
expect(subHeading).toBeInTheDocument();
20+
});
21+
22+
test('renders the RemoteButton with fallback', async () => {
23+
render(<App />);
24+
const remoteButton = await screen.findByTestId('remote-button');
25+
expect(remoteButton).toBeInTheDocument();
26+
});
27+
});

unit-test/host/jest.config.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
moduleNameMapper: {
3+
'^@src/(.*)$': '<rootDir>/src/$1'
4+
},
5+
testEnvironment: 'jsdom',
6+
transform: {
7+
'^.+\\.jsx?$': 'babel-jest'
8+
},
9+
setupFiles: ['<rootDir>/jest.setup.js']
10+
};

unit-test/host/jest.setup.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const { setupFederationTest } = require('../mf-test');
2+
3+
module.exports = async () => {
4+
await setupFederationTest(require('./modulefederation.config'));
5+
};
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const { dependencies } = require('./package.json');
2+
3+
module.exports = {
4+
name: 'host',
5+
library: {type: 'commonjs-module', name: 'host'},
6+
remoteType: 'script',
7+
remotes: {
8+
remote: 'remote@http://localhost:3002/remoteEntry.js',
9+
},
10+
shared: {
11+
...dependencies,
12+
react: {
13+
singleton: true,
14+
requiredVersion: dependencies['react'],
15+
},
16+
'react-dom': {
17+
singleton: true,
18+
requiredVersion: dependencies['react-dom'],
19+
},
20+
},
21+
};

unit-test/host/package.json

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"name": "unit_test_host",
3+
"version": "0.0.0",
4+
"dependencies": {
5+
"deasync": "^0.1.29",
6+
"fibers": "^5.0.3",
7+
"future": "^2.3.1",
8+
"react": "17.0.2",
9+
"react-dom": "17.0.2",
10+
"sync-promise": "^1.1.0"
11+
},
12+
"scripts": {
13+
"start": "rsbuild dev",
14+
"build": "rsbuild build",
15+
"preview": "rsbuild preview",
16+
"test": "jest"
17+
},
18+
"eslintConfig": {},
19+
"browserslist": {
20+
"production": [
21+
">0.2%",
22+
"not dead",
23+
"not op_mini all"
24+
],
25+
"development": [
26+
"last 1 chrome version",
27+
"last 1 firefox version",
28+
"last 1 safari version"
29+
]
30+
},
31+
"devDependencies": {
32+
"@babel/preset-env": "^7.24.5",
33+
"@babel/preset-react": "^7.24.1",
34+
"@module-federation/enhanced": "^0.1.13",
35+
"@module-federation/runtime": "^0.1.13",
36+
"@rsbuild/core": "0.6.15",
37+
"@rsbuild/plugin-react": "0.6.15",
38+
"@rspack/core": "0.6.5",
39+
"babel-jest": "^29.7.0",
40+
"jest": "^29.7.0",
41+
"jest-environment-jsdom": "^29.7.0",
42+
"node-fetch": "2.6.9"
43+
}
44+
}

unit-test/host/public/favicon.ico

3.78 KB
Binary file not shown.

unit-test/host/public/index.html

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<title>Host</title>
8+
</head>
9+
<body>
10+
<noscript>You need to enable JavaScript to run this app.</noscript>
11+
<div id="root"></div>
12+
</body>
13+
</html>

unit-test/host/rsbuild.config.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { defineConfig } from '@rsbuild/core';
2+
import { pluginReact } from '@rsbuild/plugin-react';
3+
import {ModuleFederationPlugin} from '@module-federation/enhanced/rspack'
4+
//@ts-ignore
5+
import mfConfig from './modulefederation.config';
6+
import rspack from '@rspack/core';
7+
8+
const rsbuildPlugin = () => ({
9+
name: 'example',
10+
setup(api) {
11+
api.onAfterBuild(() => console.log('done'));
12+
},
13+
});
14+
15+
export default defineConfig({
16+
server: {
17+
port: 3000,
18+
},
19+
output: {
20+
targets: ['node'],
21+
},
22+
plugins: [pluginReact()],
23+
tools: {
24+
rspack: (config, { appendPlugins }) => {
25+
appendPlugins([
26+
new ModuleFederationPlugin(mfConfig),
27+
]);
28+
},
29+
},
30+
});

unit-test/host/scripts/build.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
process.env.NODE_ENV = 'production';
2+
require('./overrides/webpack-config');
3+
require('react-scripts/scripts/build');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const { ModuleFederationPlugin } = require('webpack').container;
2+
3+
const webpackConfigPath = 'react-scripts/config/webpack.config';
4+
const webpackConfig = require(webpackConfigPath);
5+
6+
const override = config => {
7+
config.plugins.push(new ModuleFederationPlugin(require('../../modulefederation.config.js')));
8+
9+
config.output.publicPath = 'auto';
10+
11+
return config;
12+
};
13+
14+
require.cache[require.resolve(webpackConfigPath)].exports = env => override(webpackConfig(env));
15+
16+
module.exports = require(webpackConfigPath);

unit-test/host/scripts/start.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
2+
require('./overrides/webpack-config');
3+
require('react-scripts/scripts/start');

unit-test/host/src/App.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react';
2+
import RemoteButton from 'remote/Button'
3+
// const RemoteButton = React.lazy(() => import('remote/Button'));
4+
5+
const App = () => (
6+
<div>
7+
<h1 data-testid="main-heading">Basic Host-Remote</h1>
8+
<h2 data-testid="sub-heading">Host</h2>
9+
<React.Suspense fallback={<span data-testid="loading-fallback">Loading Button</span>}>
10+
<RemoteButton data-testid="remote-button" />
11+
</React.Suspense>
12+
</div>
13+
);
14+
15+
export default App;

unit-test/host/src/bootstrap.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// import React from 'react';
2+
// import ReactDOM from 'react-dom';
3+
//
4+
// import App from './App';
5+
//
6+
// ReactDOM.render(
7+
// <React.StrictMode>
8+
// <App />
9+
// </React.StrictMode>,
10+
// // document.getElementById('root'),
11+
// );

unit-test/host/src/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import('./bootstrap');

unit-test/host/thing.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require('./jest.setup')()

0 commit comments

Comments
 (0)