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

Test(web): Introduce SASS unit tests #1118

Merged
merged 1 commit into from
Nov 28, 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
9 changes: 9 additions & 0 deletions packages/web/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ Now use the reference from the theme in component styles:
- `% yarn test` for test package (lint, format, unit testing, types)
- `% yarn test:unit` for unit tests

### SASS Unit Testing

We use [sass-true][sass-true] for unit testing of our SASS components. The
tests are located in `src/scss/components/<ComponentName>/__tests__` and are
named `<ComponentName>.test.scss`. The tests are run as a part of the Jest
testing suite. Our primary focus is on testing mixins and functions as they
are the most complex parts of our SASS components.

## Migrating Your Components to Spirit

### Code Conventions
Expand Down Expand Up @@ -196,3 +204,4 @@ in a special way. Read more about it in
[design-tokens-faq]: https://github.com/lmc-eu/spirit-design-system/tree/main/packages/design-tokens#faq
[sass-modules]: https://sass-lang.com/blog/the-module-system-is-launched
[es modules]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
[sass-true]: https://github.com/oddbird/true
5 changes: 4 additions & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"examples:build": "vite build",
"examples:build:gh": "yarn examples:build --base=/spirit-design-system/",
"examples:preview": "vite preview",
"prebuild": "shx rm -rf dist && shx mkdir -p dist/scss && shx cp package.json README.md dist/ && shx cp -r src/scss dist/",
"prebuild": "shx rm -rf dist && shx mkdir -p dist/scss && shx cp package.json README.md dist/ && shx cp -r src/scss dist/ && shx rm -rf dist/scss/**/__tests__",
"build": "npm-run-all --serial design-tokens:build css js",
"precss": "yarn css:lint",
"css": "yarn css:compile && yarn css:prefix && yarn css:minify",
Expand Down Expand Up @@ -67,12 +67,15 @@
"@types/jest": "29.5.8",
"autoprefixer": "10.4.16",
"clean-css-cli": "5.6.2",
"glob": "10.3.10",
"jest-environment-jsdom": "29.7.0",
"jest-environment-node-single-context": "29.1.0",
"postcss": "8.4.31",
"postcss-cli": "10.1.0",
"resize-observer-polyfill": "1.5.1",
"rollup": "3.29.4",
"sass": "1.69.5",
"sass-true": "7.0.0",
"shx": "0.3.4",
"stylelint": "15.11.0",
"stylelint-config-prettier": "9.0.5",
Expand Down
82 changes: 82 additions & 0 deletions packages/web/src/scss/tools/__tests__/_accessibility.test.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// stylelint-disable scss/at-mixin-argumentless-call-parentheses -- We need to allow this to make sass-true work
@use 'true';
crishpeen marked this conversation as resolved.
Show resolved Hide resolved
@use '../accessibility';

@include true.describe('hide-text mixin') {
@include true.it('should output styles to visually hide text') {
@include true.assert {
@include true.output {
.text-hidden {
@include accessibility.hide-text();
}
}

@include true.expect {
.text-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
}
}
}
}

@include true.describe('min-tap-target mixin') {
@include true.it('should output styles for default centered tap target') {
@include true.assert {
@include true.output {
.tap-target-centered {
@include accessibility.min-tap-target(40px);
}
}

@include true.expect {
.tap-target-centered {
position: relative;
}

// stylelint-disable order/properties-order -- Disabling rule due to conditional rendering affecting property order
.tap-target-centered::before {
content: '';
position: absolute;
width: 40px;
height: 40px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
// stylelint-enable order/properties-order
}
}
}

@include true.it('should output styles for non-centered tap target') {
@include true.assert {
@include true.output {
.tap-target-non-centered {
@include accessibility.min-tap-target(40px, false);
}
}

@include true.expect {
.tap-target-non-centered {
position: relative;
}

.tap-target-non-centered::before {
content: '';
position: absolute;
width: 40px;
height: 40px;
}
}
}
}
}
83 changes: 83 additions & 0 deletions packages/web/src/scss/tools/__tests__/_breakpoint.test.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// stylelint-disable scss/at-mixin-argumentless-call-parentheses -- We need to allow this to make sass-true work
@use 'true';
@use '../breakpoint';

@include true.describe('up mixin from breakpoint') {
@include true.it('should output media query for provided breakpoint value') {
@include true.assert {
@include true.output {
@include breakpoint.up(600px) {
.selector {
color: #bada55;
}
}
}

@include true.expect {
@media (min-width: 600px) {
.selector {
color: #bada55;
}
}
}
}
}

@include true.it('should output styles directly without media query for 0 value') {
@include true.assert {
@include true.output {
@include breakpoint.up(0) {
.selector {
color: #bada55;
}
}
}

@include true.expect {
.selector {
color: #bada55;
}
}
}
}
}

@include true.describe('down mixin from breakpoint') {
@include true.it('should output media query for provided breakpoint value') {
@include true.assert {
@include true.output {
@include breakpoint.down(600px) {
.selector {
color: #bada55;
}
}
}

@include true.expect {
@media (max-width: 599px) {
.selector {
color: #bada55;
}
}
}
}
}

@include true.it('should output styles directly without media query for 0 value') {
@include true.assert {
@include true.output {
@include breakpoint.down(0) {
.selector {
color: #bada55;
}
}
}

@include true.expect {
.selector {
color: #bada55;
}
}
}
}
}
170 changes: 170 additions & 0 deletions packages/web/src/scss/tools/__tests__/_dictionaries.test.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// stylelint-disable scss/at-mixin-argumentless-call-parentheses
@use 'true';
@use '../../settings/dictionaries' as dictionaries-settings;
@use '../dictionaries';
@use '@tokens' as tokens;

@include true.describe('generate-colors mixin') {
@include true.it('should generate correct color classes based on a dictionary') {
@include true.assert {
@include true.output {
@include dictionaries.generate-colors(
'Test',
('primary'),
(
color: 'default',
)
);
}

@include true.expect {
.Test--primary {
--test-color: #29616f;

color: var(--test-color);
}
}
}
}
}

@include true.describe('generate-link-colors mixin') {
@include true.it('should generate correct link color classes based on a dictionary') {
@include true.assert {
@include true.output {
@include dictionaries.generate-link-colors(
'.link',
dictionaries-settings.$action-link-colors,
tokens.$action-colors,
(default, hover, active, disabled)
);
}

@include true.expect {
.link-primary {
color: #29616f;
}

.link-primary:hover {
color: #1b5260;
}

.link-primary:active {
color: #0b3a46;
}

.link-primary.link-disabled {
color: #c4c4c4;
}

.link-secondary {
color: #90a2a7;
}

.link-secondary:hover {
color: #849499;
}

.link-secondary:active {
color: #6e7b80;
}

.link-secondary.link-disabled {
color: #c4c4c4;
}

.link-inverted {
color: #e9e9e9;
}

.link-inverted:hover {
color: #dbdbdb;
}

.link-inverted:active {
color: #d4d4d4;
}

.link-inverted.link-disabled {
color: #c4c4c4;
}
}
}
}
}

@include true.describe('generate-placements mixin') {
@include true.it('should generate correct placement classes based on a dictionary') {
@include true.assert {
@include true.output {
@include dictionaries.generate-placements('Test', ('top-left'));
}

@include true.expect {
.Test--topLeft {
--test-offset: 0;

inset: auto auto 100% 0;
translate: var(--test-offset-orthogonal, 0) calc(-1 * var(--test-offset, 0));
transform-origin: bottom right;
}
}
}
}
}

// Create Test classes in order to test extend in next mixin test
.Test--topLeft,
.Test--bottomRight {
position: relative;
}

@include true.describe('generate-controlled-placements mixin') {
@include true.it('should generate correct controlled placement classes based on a dictionary') {
@include true.assert {
@include true.output {
@include dictionaries.generate-controlled-placements(
'Test',
('top-left', 'bottom-right'),
'data-placement'
);
}

@include true.expect {
// stylelint-disable scss/at-extend-no-missing-placeholder -- We are extending classes created by generate-placements().
.Test[data-placement='topLeft'] {
@extend .Test--topLeft !optional;
}

.Test[data-placement='bottomRight'] {
@extend .Test--bottomRight !optional;
}
// stylelint-enable scss/at-extend-no-missing-placeholder
}
}
}
}

@include true.describe('generate-sizes mixin') {
@include true.it('should generate correct size classes based on a config') {
@include true.assert {
@include true.output {
@include dictionaries.generate-sizes(
'TestSize',
(
large: (
padding-y: 12px,
padding-x: 16px,
),
)
);
}

@include true.expect {
.TestSize--large {
padding: 12px 16px;
}
}
}
}
}
Loading