Skip to content

Commit

Permalink
Test(web): Introduce SASS unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
crishpeen committed Nov 7, 2023
1 parent 3c0f08b commit 8e06cfe
Show file tree
Hide file tree
Showing 18 changed files with 836 additions and 21 deletions.
8 changes: 8 additions & 0 deletions packages/web/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ 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. We aim to have 100% coverage of our mixins and functions.

## Migrating Your Components to Spirit

### Code Conventions
Expand Down Expand Up @@ -196,3 +203,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
3 changes: 3 additions & 0 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,15 @@
"@types/jest": "29.5.6",
"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.4",
"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';
@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:any-link {
color: #c4c4c4;
}

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

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

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

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

.link-inverted {
color: #e9e9e9;
}

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

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

.link-inverted.link-disabled:any-link {
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

0 comments on commit 8e06cfe

Please sign in to comment.