Skip to content

Commit 783d3d2

Browse files
committed
Wip au-toaster conversion
Still struggling with the custom toaster component types
1 parent 25ddc68 commit 783d3d2

File tree

2 files changed

+68
-40
lines changed

2 files changed

+68
-40
lines changed

addon/components/au-toaster.gjs addon/components/au-toaster.gts

+14-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
1-
/* eslint-disable no-undef -- This is a workaround for a false-positive bug: https://github.com/ember-cli/eslint-plugin-ember/issues/1747 */
2-
import { AuAlert } from '@appuniversum/ember-appuniversum';
31
import { fn } from '@ember/helper';
4-
import { inject as service } from '@ember/service';
2+
import { service } from '@ember/service';
53
import Component from '@glimmer/component';
4+
import AuAlert from './au-alert';
5+
import type ToasterService from '../services/toaster';
6+
import type { ToastData } from '../services/toaster';
67

7-
export default class AuToaster extends Component {
8-
@service toaster;
8+
export interface AuToasterSignature {
9+
Args: {
10+
position?: 'top' | 'bottom';
11+
};
12+
Element: HTMLDivElement;
13+
}
14+
15+
export default class AuToaster extends Component<AuToasterSignature> {
16+
@service declare toaster: ToasterService;
917

1018
get position() {
1119
if (this.args.position == 'bottom') return 'au-c-toaster--bottom';
1220
else return 'au-c-toaster--top';
1321
}
1422

15-
closeToast = (toast) => {
23+
closeToast = (toast: ToastData) => {
1624
this.toaster.close(toast);
1725
};
1826

tests/integration/components/au-toaster-test.js tests/integration/components/au-toaster-test.gts

+54-34
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
import { setComponentTemplate } from '@ember/component';
2-
import templateOnlyComponent from '@ember/component/template-only';
1+
import AuToaster from '@appuniversum/ember-appuniversum/components/au-toaster';
2+
import type ToasterService from '@appuniversum/ember-appuniversum/services/toaster';
3+
import type {
4+
CustomToastSignature,
5+
ToastOptions,
6+
} from '@appuniversum/ember-appuniversum/services/toaster';
7+
import type { TOC } from '@ember/component/template-only';
8+
import { on } from '@ember/modifier';
39
import {
410
click,
511
getRootElement,
612
render,
713
settled,
814
waitUntil,
15+
type TestContext as BaseTestContext,
916
} from '@ember/test-helpers';
1017
import { queryByText } from '@testing-library/dom';
1118
import { setupRenderingTest } from 'dummy/tests/helpers';
12-
import { hbs } from 'ember-cli-htmlbars';
1319
import { module, test } from 'qunit';
1420

1521
const TOASTER = {
@@ -18,15 +24,19 @@ const TOASTER = {
1824
CLOSE: '[data-test-alert-close]',
1925
};
2026

27+
interface TestContext extends BaseTestContext {
28+
toaster: ToasterService;
29+
}
30+
2131
module('Integration | Component | au-toaster', function (hooks) {
2232
setupRenderingTest(hooks);
2333

24-
hooks.beforeEach(async function () {
25-
this.toaster = this.owner.lookup('service:toaster');
34+
hooks.beforeEach<TestContext>(async function () {
35+
this.toaster = this.owner.lookup('service:toaster') as ToasterService;
2636
await renderToasterContainer();
2737
});
2838

29-
test('it only renders the container if toasts are present', async function (assert) {
39+
test<TestContext>('it only renders the container if toasts are present', async function (assert) {
3040
assert.dom(TOASTER.CONTAINER).doesNotExist();
3141

3242
this.toaster.notify('Bar', 'Foo');
@@ -35,7 +45,7 @@ module('Integration | Component | au-toaster', function (hooks) {
3545
assert.dom(TOASTER.CONTAINER).exists();
3646
});
3747

38-
test('it has different methods to show styled toasts', async function (assert) {
48+
test<TestContext>('it has different methods to show styled toasts', async function (assert) {
3949
this.toaster.notify('toast', 'notify');
4050
this.toaster.success('toast', 'success');
4151
this.toaster.warning('toast', 'warning');
@@ -48,48 +58,48 @@ module('Integration | Component | au-toaster', function (hooks) {
4858
.exists({ count: 5 }, 'it displays a toast for every method call');
4959
});
5060

51-
test('`notify` displays the title and message', async function (assert) {
61+
test<TestContext>('`notify` displays the title and message', async function (assert) {
5262
this.toaster.notify('toast', 'notify');
5363
await settled();
5464

5565
assert.dom(TOASTER.TOAST).containsText('notify toast');
5666
});
5767

58-
test('`success` displays the title and message', async function (assert) {
68+
test<TestContext>('`success` displays the title and message', async function (assert) {
5969
this.toaster.success('toast', 'success');
6070
await settled();
6171

6272
assert.dom(TOASTER.TOAST).containsText('success toast');
6373
});
6474

65-
test('`warning` displays the title and message', async function (assert) {
75+
test<TestContext>('`warning` displays the title and message', async function (assert) {
6676
this.toaster.success('toast', 'warning');
6777
await settled();
6878

6979
assert.dom(TOASTER.TOAST).containsText('warning toast');
7080
});
7181

72-
test('`error` displays the title and message', async function (assert) {
82+
test<TestContext>('`error` displays the title and message', async function (assert) {
7383
this.toaster.success('toast', 'error');
7484
await settled();
7585

7686
assert.dom(TOASTER.TOAST).containsText('error toast');
7787
});
7888

79-
test('`loading` displays the title and message', async function (assert) {
89+
test<TestContext>('`loading` displays the title and message', async function (assert) {
8090
this.toaster.success('toast', 'loading');
8191
await settled();
8292

8393
assert.dom(TOASTER.TOAST).containsText('loading toast');
8494
});
8595

86-
test('toasts can be configured to be closable', async function (assert) {
96+
test<TestContext>('toasts can be configured to be closable', async function (assert) {
8797
this.toaster.notify('toast', 'closable');
8898
await settled();
8999

90-
let toast = getRootElement().querySelector(TOASTER.TOAST);
100+
let toast = getRootElement().querySelector(TOASTER.TOAST) as HTMLElement;
91101
assert.dom(toast).exists();
92-
let closeButton = queryByText(toast, 'Sluit');
102+
let closeButton = queryByText(toast, 'Sluit') as HTMLButtonElement;
93103
assert.dom(closeButton).exists('Toasts are closable by default');
94104

95105
await click(closeButton);
@@ -100,16 +110,16 @@ module('Integration | Component | au-toaster', function (hooks) {
100110
this.toaster.notify('toast', 'non-closable', { closable: false });
101111
await settled();
102112

103-
toast = getRootElement().querySelector(TOASTER.TOAST);
113+
toast = getRootElement().querySelector(TOASTER.TOAST) as HTMLElement;
104114
assert.dom(toast).exists();
105-
closeButton = queryByText(toast, 'Sluit');
115+
closeButton = queryByText(toast, 'Sluit') as HTMLButtonElement;
106116

107117
assert
108118
.dom(closeButton)
109119
.doesNotExist('The close button is hidden if the alert is not closable');
110120
});
111121

112-
test('toasts can be configured to auto-close after a certain time', async function (assert) {
122+
test<TestContext>('toasts can be configured to auto-close after a certain time', async function (assert) {
113123
this.toaster.notify('toast', 'auto-closing', { timeOut: 20 });
114124

115125
// We can't use `await settled();` here since it seemingly waits for the timeOut duration as well
@@ -123,8 +133,8 @@ module('Integration | Component | au-toaster', function (hooks) {
123133
});
124134
});
125135

126-
test('toasts can be closed with the `close` method', async function (assert) {
127-
let toast = this.toaster.notify('toast', 'notify');
136+
test<TestContext>('toasts can be closed with the `close` method', async function (assert) {
137+
const toast = this.toaster.notify('toast', 'notify');
128138
assert.ok(toast, 'display methods return a toast object');
129139
await settled();
130140

@@ -135,26 +145,36 @@ module('Integration | Component | au-toaster', function (hooks) {
135145
assert.dom(TOASTER.TOAST).doesNotExist();
136146
});
137147

138-
test('custom toast components can be used', async function (assert) {
148+
test<TestContext>('custom toast components can be used', async function (assert) {
139149
const CUSTOM_TOAST = '[data-test-custom-toast]';
140-
const CustomToast = setComponentTemplate(
141-
hbs`<div data-test-custom-toast>
142-
<p>
143-
{{@options.foo}}
144-
</p>
145-
<button {{on "click" @close}} type="button">Close me</button>
146-
</div>`,
147-
templateOnlyComponent(),
148-
);
150+
interface ToastOptionsWithFoo extends ToastOptions {
151+
foo: string;
152+
}
153+
154+
const CustomToast: TOC<{
155+
Args: {
156+
options: ToastOptionsWithFoo;
157+
// options: ToastOptions; // Doesn't work
158+
// options: ToastOptions & { foo: string }; // Doesn't work
159+
close: CustomToastSignature['Args']['close'];
160+
};
161+
}> = <template>
162+
<div data-test-custom-toast>
163+
<p>
164+
{{@options.foo}}
165+
</p>
166+
<button {{on "click" @close}} type="button">Close me</button>
167+
</div>
168+
</template>;
149169

150170
this.toaster.show(CustomToast, { foo: 'Foo' });
151171
await settled();
152172

153-
const toastElement = getRootElement().querySelector(CUSTOM_TOAST);
173+
const toastElement = getRootElement().querySelector(CUSTOM_TOAST) as HTMLElement;
154174
assert.dom(toastElement).exists();
155175

156176
assert.dom(toastElement.querySelector('p')).containsText('Foo');
157-
await click(queryByText(toastElement, 'Close me'));
177+
await click(queryByText(toastElement, 'Close me') as HTMLButtonElement);
158178

159179
assert
160180
.dom(CUSTOM_TOAST)
@@ -177,10 +197,10 @@ module('Integration | Component | au-toaster', function (hooks) {
177197
});
178198

179199
async function renderToasterContainer() {
180-
await render(hbs`<AuToaster data-test-toaster-container />`);
200+
await render(<template><AuToaster data-test-toaster-container /></template>);
181201
}
182202

183-
function timeout(delay) {
203+
function timeout(delay: number) {
184204
return new Promise((resolve) => {
185205
setTimeout(resolve, delay);
186206
});

0 commit comments

Comments
 (0)