Skip to content

Commit 8f3aef2

Browse files
committed
Add tests for CSS Modules with React
1 parent dbd5e5d commit 8f3aef2

14 files changed

+153
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import './styles.css';
2+
import './styles.less';
3+
import './styles.scss';
4+
import './styles.stylus';
5+
import stylesCss from './styles.module.css?module';
6+
import stylesLess from './styles.module.less?module';
7+
import stylesScss from './styles.module.scss?module';
8+
import stylesStylus from './styles.module.stylus?module';
9+
10+
export default function App() {
11+
return <div className={`red large justified lowercase ${stylesCss.italic} ${stylesLess.underline} ${stylesScss.bold} ${stylesStylus.rtl}`}></div>
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.red {
2+
color: red;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.justified {
2+
text-align: justify;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.italic {
2+
font-style: italic;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.underline {
2+
text-decoration: underline;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.bold {
2+
font-weight: bold;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.rtl
2+
direction: rtl;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.large {
2+
font-size: 50px;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.lowercase
2+
text-transform: lowercase

fixtures/react-css-modules/main.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import {createRoot} from 'react-dom/client';
2+
import App from './components/App';
3+
4+
const root = createRoot(document.getElementById('app'));
5+
6+
root.render(<App />);

lib/loaders/babel.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ module.exports = {
7070
if (webpackConfig.useReact) {
7171
loaderFeatures.ensurePackagesExistAndAreCorrectVersion('react');
7272

73-
babelConfig.presets.push(require.resolve('@babel/preset-react'));
73+
babelConfig.presets.push([require.resolve('@babel/preset-react'), {
74+
// TODO: To remove when Babel 8, "automatic" will become the default value
75+
runtime: 'automatic',
76+
}]);
7477
}
7578

7679
if (webpackConfig.usePreact) {

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"@babel/eslint-parser": "^7.17.0",
4949
"@babel/plugin-transform-react-jsx": "^7.12.11",
5050
"@babel/preset-env": "^7.16.0",
51-
"@babel/preset-react": "^7.0.0",
51+
"@babel/preset-react": "^7.9.0",
5252
"@babel/preset-typescript": "^7.0.0",
5353
"@hotwired/stimulus": "^3.0.0",
5454
"@symfony/mock-module": "file:fixtures/stimulus/mock-module",
@@ -81,6 +81,8 @@
8181
"preact": "^10.5.0",
8282
"preact-compat": "^3.17.0",
8383
"puppeteer": "^23.2.2",
84+
"react": "^18.0.0",
85+
"react-dom": "^18.0.0",
8486
"sass": "^1.17.0",
8587
"sass-loader": "^16.0.1",
8688
"sinon": "^14.0.0",

test/functional.js

+82-1
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,88 @@ module.exports = {
17201720
});
17211721
});
17221722

1723+
it('React supports CSS/Sass/Less/Stylus modules', (done) => {
1724+
const appDir = testSetup.createTestAppDir();
1725+
const config = testSetup.createWebpackConfig(appDir, 'www/build', 'dev');
1726+
config.enableSingleRuntimeChunk();
1727+
config.setPublicPath('/build');
1728+
config.addEntry('main', './react-css-modules/main.js');
1729+
config.enableReactPreset();
1730+
config.enableSassLoader();
1731+
config.enableLessLoader();
1732+
config.enableStylusLoader();
1733+
config.configureCssLoader(options => {
1734+
// Remove hashes from local ident names
1735+
// since they are not always the same.
1736+
if (options.modules) {
1737+
options.modules.localIdentName = '[local]_foo';
1738+
}
1739+
});
1740+
1741+
// Enable the PostCSS loader so we can use `lang="postcss"`
1742+
config.enablePostCssLoader();
1743+
fs.writeFileSync(
1744+
path.join(appDir, 'postcss.config.js'),
1745+
`
1746+
module.exports = {
1747+
plugins: [
1748+
require('autoprefixer')()
1749+
]
1750+
} `
1751+
);
1752+
1753+
testSetup.runWebpack(config, (webpackAssert) => {
1754+
expect(config.outputPath).to.be.a.directory().with.deep.files([
1755+
'main.js',
1756+
'main.css',
1757+
'manifest.json',
1758+
'entrypoints.json',
1759+
'runtime.js',
1760+
]);
1761+
1762+
const expectClassDeclaration = (className) => {
1763+
webpackAssert.assertOutputFileContains(
1764+
'main.css',
1765+
`.${className} {`
1766+
);
1767+
};
1768+
1769+
expectClassDeclaration('red'); // Standard CSS
1770+
expectClassDeclaration('large'); // Standard SCSS
1771+
expectClassDeclaration('justified'); // Standard Less
1772+
expectClassDeclaration('lowercase'); // Standard Stylus
1773+
1774+
expectClassDeclaration('italic_foo'); // CSS Module
1775+
expectClassDeclaration('bold_foo'); // SCSS Module
1776+
expectClassDeclaration('underline_foo'); // Less Module
1777+
expectClassDeclaration('rtl_foo'); // Stylus Module
1778+
1779+
testSetup.requestTestPage(
1780+
browser,
1781+
path.join(config.getContext(), 'www'),
1782+
[
1783+
'build/runtime.js',
1784+
'build/main.js'
1785+
],
1786+
async({ page }) => {
1787+
const divClassArray = await page.evaluate(() => Array.from(document.body.querySelector('#app > div').classList.values()));
1788+
1789+
expect(divClassArray.includes('red')).to.be.true; // Standard CSS
1790+
expect(divClassArray.includes('large')).to.be.true; // Standard SCSS
1791+
expect(divClassArray.includes('justified')).to.be.true; // Standard Less
1792+
expect(divClassArray.includes('lowercase')).to.be.true; // Standard Stylus
1793+
1794+
expect(divClassArray.includes('italic_foo')).to.be.true; // CSS module
1795+
expect(divClassArray.includes('bold_foo')).to.be.true; // SCSS module
1796+
expect(divClassArray.includes('underline_foo')).to.be.true; // Less module
1797+
expect(divClassArray.includes('rtl_foo')).to.be.true; // Stylus module
1798+
1799+
done();
1800+
}
1801+
);
1802+
});
1803+
});
1804+
17231805
it('Preact supports CSS/Sass/Less/Stylus modules', (done) => {
17241806
const appDir = testSetup.createTestAppDir();
17251807
const config = testSetup.createWebpackConfig(appDir, 'www/build', 'dev');
@@ -1802,7 +1884,6 @@ module.exports = {
18021884
});
18031885
});
18041886

1805-
18061887
it('Vue.js error when using non-activated loaders', (done) => {
18071888
const config = createWebpackConfig('www/build', 'dev');
18081889
config.setPublicPath('/build');

yarn.lock

+24-2
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@
975975
"@babel/types" "^7.4.4"
976976
esutils "^2.0.2"
977977

978-
"@babel/preset-react@^7.0.0":
978+
"@babel/preset-react@^7.9.0":
979979
version "7.24.7"
980980
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.24.7.tgz#480aeb389b2a798880bf1f889199e3641cbb22dc"
981981
integrity sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==
@@ -4851,7 +4851,7 @@ log-symbols@^4.1.0:
48514851
chalk "^4.1.0"
48524852
is-unicode-supported "^0.1.0"
48534853

4854-
loose-envify@^1.0.0, loose-envify@^1.4.0:
4854+
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
48554855
version "1.4.0"
48564856
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
48574857
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -5918,11 +5918,26 @@ [email protected]:
59185918
iconv-lite "0.4.24"
59195919
unpipe "1.0.0"
59205920

5921+
react-dom@^18.0.0:
5922+
version "18.3.1"
5923+
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
5924+
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
5925+
dependencies:
5926+
loose-envify "^1.1.0"
5927+
scheduler "^0.23.2"
5928+
59215929
react-is@^16.13.1:
59225930
version "16.13.1"
59235931
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
59245932
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
59255933

5934+
react@^18.0.0:
5935+
version "18.3.1"
5936+
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
5937+
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
5938+
dependencies:
5939+
loose-envify "^1.1.0"
5940+
59265941
readable-stream@^2.0.1:
59275942
version "2.3.8"
59285943
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
@@ -6183,6 +6198,13 @@ sax@~1.3.0:
61836198
resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0"
61846199
integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==
61856200

6201+
scheduler@^0.23.2:
6202+
version "0.23.2"
6203+
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
6204+
integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
6205+
dependencies:
6206+
loose-envify "^1.1.0"
6207+
61866208
schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0:
61876209
version "3.3.0"
61886210
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"

0 commit comments

Comments
 (0)