-
Notifications
You must be signed in to change notification settings - Fork 49
[Project Solar / Phase 1 / Engineering Follow-ups] Add tests for HDS theming service and components #3428
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
[Project Solar / Phase 1 / Engineering Follow-ups] Add tests for HDS theming service and components #3428
Changes from all commits
e94056c
b578ac9
3fa0e53
78c8465
5456453
dcaa2d0
59f1be4
48d4a36
71b25cf
4c653cb
e8bc956
b75728d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| /** | ||
| * Copyright (c) HashiCorp, Inc. | ||
| * SPDX-License-Identifier: MPL-2.0 | ||
| */ | ||
|
|
||
| import { module, test } from 'qunit'; | ||
| import { visit } from '@ember/test-helpers'; | ||
| import { setupApplicationTest } from 'showcase/tests/helpers'; | ||
| import { a11yAudit } from 'ember-a11y-testing/test-support'; | ||
|
|
||
| module('Acceptance | Foundations | hds/theming', function (hooks) { | ||
| setupApplicationTest(hooks); | ||
|
|
||
| test('Foundations/hds/theming page passes automated a11y checks', async function (assert) { | ||
| await visit('/foundations/theming'); | ||
| await a11yAudit(); | ||
|
|
||
| assert.ok(true, 'a11y automation audit passed'); | ||
| }); | ||
| }); |
didoo marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| /** | ||
| * Copyright (c) HashiCorp, Inc. | ||
| * SPDX-License-Identifier: MPL-2.0 | ||
| */ | ||
|
|
||
| import { module, test } from 'qunit'; | ||
| import { setupRenderingTest } from 'showcase/tests/helpers'; | ||
| import { render, resetOnerror, setupOnerror } from '@ember/test-helpers'; | ||
| import { hbs } from 'ember-cli-htmlbars'; | ||
|
|
||
| import { | ||
| CONTEXTUAL_THEMES, | ||
| CONTEXTUAL_MODES, | ||
| } from '@hashicorp/design-system-components/components/hds/theme-context/index'; | ||
|
|
||
| module('Integration | Component | hds/theme-context/index', function (hooks) { | ||
| setupRenderingTest(hooks); | ||
|
|
||
| hooks.afterEach(() => { | ||
| resetOnerror(); | ||
| }); | ||
|
|
||
| test('it should render the component with a CSS class that matches the component name', async function (assert) { | ||
| await render( | ||
| hbs`<Hds::ThemeContext @context="light" id="test-theme-context" />`, | ||
| ); | ||
| assert.dom('#test-theme-context').hasClass('hds-theme-context'); | ||
| }); | ||
|
|
||
| // CONTEXT - THEMES | ||
|
|
||
| CONTEXTUAL_THEMES.forEach((context) => { | ||
| test(`it should render the correct CSS "theme" class for "${context}" context`, async function (assert) { | ||
| this.set('context', context); | ||
| await render( | ||
| hbs`<Hds::ThemeContext @context={{this.context}} id="test-theme-context" />`, | ||
| ); | ||
| assert.dom('#test-theme-context').hasClass(`hds-theme-${context}`); | ||
| }); | ||
| }); | ||
|
|
||
| // CONTEXT - MODES | ||
|
|
||
| CONTEXTUAL_MODES.forEach((context) => { | ||
| test(`it should render the correct CSS "mode" class for "${context}" context`, async function (assert) { | ||
| this.set('context', context); | ||
| await render( | ||
| hbs`<Hds::ThemeContext @context={{this.context}} id="test-theme-context" />`, | ||
| ); | ||
| assert.dom('#test-theme-context').hasClass(`hds-mode-${context}`); | ||
| }); | ||
| }); | ||
|
|
||
| // YIELDED CONTENT | ||
|
|
||
| test('it correctly yields content passed in the default block', async function (assert) { | ||
| await render(hbs` | ||
| <Hds::ThemeContext @context="light" id="test-theme-context"> | ||
| <p id="test-content">This is yielded content</p> | ||
| </Hds::ThemeContext> | ||
| `); | ||
| assert.dom('#test-content').exists(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one seems a bit redundant perhaps.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We test to test the yielding of content. This one in particular makes sense to me, since it's one of the two main functions of this component (apply a class and yield the content) |
||
| assert.dom('#test-content').hasText('This is yielded content'); | ||
| assert.dom('#test-theme-context #test-content').exists(); | ||
| }); | ||
|
|
||
| // ASSERTIONS | ||
|
|
||
| test('it should throw an assertion if an incorrect value for @context is provided', async function (assert) { | ||
| const errorMessage = | ||
| '@context for "Hds::ThemeContext" must be one of the following: default, system, light, dark, cds-g0, cds-g10, cds-g90, cds-g100; received: foo'; | ||
| assert.expect(2); | ||
| setupOnerror(function (error) { | ||
| assert.strictEqual(error.message, `Assertion Failed: ${errorMessage}`); | ||
| }); | ||
| await render(hbs`<Hds::ThemeContext @context="foo" />`); | ||
didoo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| assert.throws(function () { | ||
| throw new Error(errorMessage); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,218 @@ | ||
| /** | ||
| * Copyright (c) HashiCorp, Inc. | ||
| * SPDX-License-Identifier: MPL-2.0 | ||
| */ | ||
|
|
||
| import { module, test } from 'qunit'; | ||
| import { setupRenderingTest } from 'showcase/tests/helpers'; | ||
| import { render, click } from '@ember/test-helpers'; | ||
| import { hbs } from 'ember-cli-htmlbars'; | ||
| import sinon from 'sinon'; | ||
|
|
||
| module('Integration | Component | hds/theme-switcher/index', function (hooks) { | ||
| setupRenderingTest(hooks); | ||
|
|
||
| hooks.beforeEach(function () { | ||
| this.themingService = this.owner.lookup('service:hds-theming'); | ||
| }); | ||
|
|
||
| hooks.afterEach(function () { | ||
| // Reset the theme after each test | ||
| this.themingService.setTheme({ theme: undefined }); | ||
| }); | ||
|
|
||
| test('it should render the component with a CSS class that matches the component name', async function (assert) { | ||
| await render(hbs`<Hds::ThemeSwitcher id="test-theme-switcher" />`); | ||
| assert.dom('#test-theme-switcher').hasClass('hds-theme-switcher-control'); | ||
| }); | ||
|
|
||
| // TOGGLE SIZE | ||
|
|
||
| test('it should render with small size by default', async function (assert) { | ||
| await render(hbs`<Hds::ThemeSwitcher id="test-theme-switcher" />`); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .hasClass('hds-dropdown-toggle-button--size-small'); | ||
| }); | ||
|
|
||
| test('it should render the correct CSS size class if @toggleSize is declared', async function (assert) { | ||
| await render( | ||
| hbs`<Hds::ThemeSwitcher @toggleSize="medium" id="test-theme-switcher" />`, | ||
| ); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .hasClass('hds-dropdown-toggle-button--size-medium'); | ||
| }); | ||
|
|
||
| // TOGGLE IS FULL WIDTH | ||
|
|
||
| test('it should not be full width by default', async function (assert) { | ||
| await render(hbs`<Hds::ThemeSwitcher id="test-theme-switcher" />`); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .doesNotHaveClass('hds-button--width-full'); | ||
| }); | ||
|
|
||
| test('it should render full width if @toggleIsFullWidth is true', async function (assert) { | ||
| await render( | ||
| hbs`<Hds::ThemeSwitcher @toggleIsFullWidth={{true}} id="test-theme-switcher" />`, | ||
| ); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .hasClass('hds-dropdown-toggle-button--width-full'); | ||
| }); | ||
|
|
||
| // THEME DISPLAY | ||
|
|
||
| test('it should display "Theme" label when no theme is set', async function (assert) { | ||
| await render(hbs`<Hds::ThemeSwitcher id="test-theme-switcher" />`); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .containsText('Theme'); | ||
| }); | ||
|
|
||
| test('it should display "System" label when system theme is set', async function (assert) { | ||
| this.themingService.setTheme({ theme: 'system' }); | ||
| await render(hbs`<Hds::ThemeSwitcher id="test-theme-switcher" />`); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .containsText('System'); | ||
| }); | ||
|
|
||
| test('it should display "Light" label when light theme is set', async function (assert) { | ||
| this.themingService.setTheme({ theme: 'light' }); | ||
| await render(hbs`<Hds::ThemeSwitcher id="test-theme-switcher" />`); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .containsText('Light'); | ||
| }); | ||
|
|
||
| test('it should display "Dark" label when dark theme is set', async function (assert) { | ||
| this.themingService.setTheme({ theme: 'dark' }); | ||
| await render(hbs`<Hds::ThemeSwitcher id="test-theme-switcher" />`); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .containsText('Dark'); | ||
| }); | ||
|
|
||
| test('it should display "Default" label when default theme is set and hasDefaultOption is true', async function (assert) { | ||
| this.themingService.setTheme({ theme: 'default' }); | ||
| await render( | ||
| hbs`<Hds::ThemeSwitcher @hasDefaultOption={{true}} id="test-theme-switcher" />`, | ||
| ); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .containsText('Default'); | ||
| }); | ||
|
|
||
| // HAS DEFAULT OPTION | ||
|
|
||
| test('it should not include the "Default" option by default', async function (assert) { | ||
| await render(hbs`<Hds::ThemeSwitcher id="test-theme-switcher" />`); | ||
| await click('#test-theme-switcher button'); | ||
| assert.dom('.hds-dropdown-list-item').exists({ count: 3 }); | ||
| assert.dom('.hds-dropdown-list-item').doesNotContainText('Default'); | ||
| }); | ||
|
|
||
| test('it should include the "Default" option when `@hasDefaultOption` is `true`', async function (assert) { | ||
| await render( | ||
| hbs`<Hds::ThemeSwitcher @hasDefaultOption={{true}} id="test-theme-switcher" />`, | ||
| ); | ||
| await click('#test-theme-switcher button'); | ||
| assert.dom('.hds-dropdown-list-item').exists({ count: 4 }); | ||
| assert.dom('.hds-dropdown-list-item').containsText('Default'); | ||
| }); | ||
|
|
||
| // HAS SYSTEM OPTION | ||
|
|
||
| test('it should include the "System" option by default', async function (assert) { | ||
| await render(hbs`<Hds::ThemeSwitcher id="test-theme-switcher" />`); | ||
| await click('#test-theme-switcher button'); | ||
| assert.dom('.hds-dropdown-list-item').containsText('System'); | ||
| }); | ||
|
|
||
| test('it should not include the "System" option when `@hasSystemOption` is `false`', async function (assert) { | ||
| await render( | ||
| hbs`<Hds::ThemeSwitcher @hasSystemOption={{false}} id="test-theme-switcher" />`, | ||
| ); | ||
| await click('#test-theme-switcher button'); | ||
| assert.dom('.hds-dropdown-list-item').exists({ count: 2 }); | ||
| assert.dom('.hds-dropdown-list-item').doesNotContainText('System'); | ||
| }); | ||
|
|
||
| // THEME SELECTION | ||
|
|
||
| test('it should update the theme in the service and the label in the toggle when a dropdown option is selected', async function (assert) { | ||
| await render( | ||
| hbs`<Hds::ThemeSwitcher @hasDefaultOption={{true}} @hasSystemOption={{true}} id="test-theme-switcher" />`, | ||
| ); | ||
|
|
||
| // open the dropdown | ||
| await click('#test-theme-switcher button'); | ||
|
|
||
| // click on `Light` theme | ||
| await click('.hds-dropdown-list-item:nth-of-type(3) button'); | ||
| assert.strictEqual( | ||
| this.themingService.currentTheme, | ||
| 'light', | ||
| 'theme service should be updated to `light`', | ||
| ); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .containsText('Light'); | ||
|
|
||
| // click on `Dark` theme | ||
| await click('.hds-dropdown-list-item:nth-of-type(4) button'); | ||
| assert.strictEqual( | ||
| this.themingService.currentTheme, | ||
| 'dark', | ||
| 'theme service should be updated to `dark`', | ||
| ); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .containsText('Dark'); | ||
|
|
||
| // click on `System` theme | ||
| await click('.hds-dropdown-list-item:nth-of-type(2) button'); | ||
| assert.strictEqual( | ||
| this.themingService.currentTheme, | ||
| 'system', | ||
| 'theme service should be updated to `system`', | ||
| ); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .containsText('System'); | ||
|
|
||
| // click on `Default` theme | ||
| await click('.hds-dropdown-list-item:nth-of-type(1) button'); | ||
| assert.strictEqual( | ||
| this.themingService.currentTheme, | ||
| 'default', | ||
| 'theme service should be updated to `undefined` (default)', | ||
| ); | ||
| assert | ||
| .dom('#test-theme-switcher .hds-dropdown-toggle-button') | ||
| .containsText('Default'); | ||
| }); | ||
|
|
||
| // CALLBACKS | ||
|
|
||
| test('it should call @onSetTheme callback when provided', async function (assert) { | ||
| const onSetTheme = sinon.spy(); | ||
|
|
||
| this.set('onSetTheme', onSetTheme); | ||
|
|
||
| await render( | ||
| hbs`<Hds::ThemeSwitcher @onSetTheme={{this.onSetTheme}} id="test-theme-switcher" />`, | ||
| ); | ||
| await click('#test-theme-switcher button'); | ||
|
|
||
| // change theme | ||
| const lightOptionButton = this.element.querySelector( | ||
| '.hds-dropdown-list-item:nth-of-type(3) button', | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there another way the button could be selected that doesn't rely solely on the DOM structure like this?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not that I could think of (we could use the inner text, but the logic would become even more complex) |
||
| ); | ||
| await click(lightOptionButton); | ||
|
|
||
| assert.true(onSetTheme.calledOnce); | ||
| }); | ||
| }); | ||
Uh oh!
There was an error while loading. Please reload this page.