@happyvertical/smrt-users 0.53.1 → 0.53.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/agents/permissions.md +7 -0
- package/dist/chunks/{TerminalAuthService-DKDfXpDG.js → TerminalAuthService-DG8HwPgq.js} +49 -26
- package/dist/chunks/TerminalAuthService-DG8HwPgq.js.map +1 -0
- package/dist/collections/RoleCollection.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -5
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +26 -18
- package/dist/migrations/deduplicateRolePermissions.d.ts +23 -0
- package/dist/migrations/deduplicateRolePermissions.d.ts.map +1 -0
- package/dist/models/RolePermission.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +9 -5
- package/dist/sveltekit.js +1 -1
- package/package.json +11 -11
- package/dist/__tests__/helpers/oidc-test-server.d.ts +0 -45
- package/dist/__tests__/helpers/oidc-test-server.d.ts.map +0 -1
- package/dist/__tests__/helpers/postgres-rls-reset.d.ts +0 -15
- package/dist/__tests__/helpers/postgres-rls-reset.d.ts.map +0 -1
- package/dist/chunks/TerminalAuthService-DKDfXpDG.js.map +0 -1
- package/dist/svelte/components/__tests__/InviteUserModal.test.js +0 -65
- package/dist/svelte/components/__tests__/UserAvatar.test.js +0 -31
- package/dist/svelte/components/__tests__/UserCard.test.js +0 -39
- package/dist/svelte/components/__tests__/UserForm.test.js +0 -50
- package/dist/svelte/components/__tests__/UserList.test.js +0 -48
- package/dist/svelte/components/__tests__/UserMenu.test.js +0 -83
- package/dist/svelte/components/__tests__/UserStatus.test.js +0 -36
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Component coverage for InviteUserModal via the shared S11 harness (#1416).
|
|
4
|
-
*/
|
|
5
|
-
import { fireEvent, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
-
import InviteUserModal from '../InviteUserModal.svelte';
|
|
8
|
-
const baseProps = (over = {}) => ({
|
|
9
|
-
open: true,
|
|
10
|
-
tenant: { name: 'Acme' },
|
|
11
|
-
roles: [{ id: 'r1', slug: 'member', name: 'Member' }],
|
|
12
|
-
onsubmit: vi.fn(),
|
|
13
|
-
onclose: vi.fn(),
|
|
14
|
-
...over,
|
|
15
|
-
});
|
|
16
|
-
describe('InviteUserModal', () => {
|
|
17
|
-
it('renders the invite dialog scoped to the tenant when open', () => {
|
|
18
|
-
render(InviteUserModal, { props: baseProps() });
|
|
19
|
-
expect(screen.getByRole('heading', { name: 'Invite User to Acme' })).toBeInTheDocument();
|
|
20
|
-
expect(screen.getByLabelText('Email address')).toBeInTheDocument();
|
|
21
|
-
expect(screen.getByRole('button', { name: 'Send Invite' })).toBeInTheDocument();
|
|
22
|
-
});
|
|
23
|
-
it('renders nothing when closed', () => {
|
|
24
|
-
render(InviteUserModal, { props: baseProps({ open: false }) });
|
|
25
|
-
expect(screen.queryByRole('dialog')).toBeNull();
|
|
26
|
-
});
|
|
27
|
-
it('shows the JS validation error when submitted with no email', async () => {
|
|
28
|
-
const onsubmit = vi.fn();
|
|
29
|
-
const { container } = render(InviteUserModal, {
|
|
30
|
-
props: baseProps({ onsubmit }),
|
|
31
|
-
});
|
|
32
|
-
// Submit the form directly to exercise the component's own guard — a button
|
|
33
|
-
// click would be pre-empted by the input's native `required` constraint.
|
|
34
|
-
const form = container.querySelector('form');
|
|
35
|
-
if (!form)
|
|
36
|
-
throw new Error('form not found');
|
|
37
|
-
await fireEvent.submit(form);
|
|
38
|
-
expect(screen.getByText('Email is required')).toBeInTheDocument();
|
|
39
|
-
expect(onsubmit).not.toHaveBeenCalled();
|
|
40
|
-
});
|
|
41
|
-
it('submits the email and default role', async () => {
|
|
42
|
-
const onsubmit = vi.fn();
|
|
43
|
-
render(InviteUserModal, { props: baseProps({ onsubmit }) });
|
|
44
|
-
await userEvent.type(screen.getByLabelText('Email address'), 'ada@example.com');
|
|
45
|
-
await userEvent.click(screen.getByRole('button', { name: 'Send Invite' }));
|
|
46
|
-
expect(onsubmit).toHaveBeenCalledWith(expect.objectContaining({ email: 'ada@example.com', roleId: 'r1' }));
|
|
47
|
-
});
|
|
48
|
-
it('closes via the Cancel button', async () => {
|
|
49
|
-
const onclose = vi.fn();
|
|
50
|
-
render(InviteUserModal, { props: baseProps({ onclose }) });
|
|
51
|
-
await userEvent.click(screen.getByRole('button', { name: 'Cancel' }));
|
|
52
|
-
expect(onclose).toHaveBeenCalledTimes(1);
|
|
53
|
-
});
|
|
54
|
-
// Regression for #1399 blocker #2: the hand-rolled dialog had no focus
|
|
55
|
-
// trap/restore. Adopting the smrt-ui Modal renders a native <dialog> (top
|
|
56
|
-
// layer + trap + inert), which supplies the trap and Escape handling the
|
|
57
|
-
// previous markup lacked.
|
|
58
|
-
it('renders inside a native <dialog> for the focus trap', () => {
|
|
59
|
-
const { container } = render(InviteUserModal, { props: baseProps() });
|
|
60
|
-
const dialog = container.querySelector('dialog');
|
|
61
|
-
expect(dialog).not.toBeNull();
|
|
62
|
-
// The form lives inside the dialog, so focus is trapped within it.
|
|
63
|
-
expect(dialog?.querySelector('form')).not.toBeNull();
|
|
64
|
-
});
|
|
65
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* First component test in smrt-users via the shared S11 harness (#1416): the
|
|
4
|
-
* Testing-Library + axe surface comes from `@happyvertical/smrt-vitest` and the
|
|
5
|
-
* jsdom + jest-dom setup from the shared `svelte-setup` wired in vitest.config.
|
|
6
|
-
*/
|
|
7
|
-
import { expectNoA11yViolations, render, screen, } from '@happyvertical/smrt-vitest/svelte';
|
|
8
|
-
import { describe, expect, it } from 'vitest';
|
|
9
|
-
import UserAvatar from '../UserAvatar.svelte';
|
|
10
|
-
// UserAvatar only reads `profile.name`, so a minimal stub is enough to drive it.
|
|
11
|
-
const profile = { name: 'Ada Lovelace' };
|
|
12
|
-
describe('UserAvatar', () => {
|
|
13
|
-
it('renders the initials derived from the profile name', () => {
|
|
14
|
-
render(UserAvatar, { props: { profile } });
|
|
15
|
-
expect(screen.getByText('AL')).toBeInTheDocument();
|
|
16
|
-
});
|
|
17
|
-
it('renders the full name when showName is set', () => {
|
|
18
|
-
render(UserAvatar, { props: { profile, showName: true } });
|
|
19
|
-
expect(screen.getByText('Ada Lovelace')).toBeInTheDocument();
|
|
20
|
-
});
|
|
21
|
-
it('falls back to "U" initials for a profile with no name', () => {
|
|
22
|
-
render(UserAvatar, { props: { profile: {} } });
|
|
23
|
-
expect(screen.getByText('U')).toBeInTheDocument();
|
|
24
|
-
});
|
|
25
|
-
it('is axe-clean', async () => {
|
|
26
|
-
const { container } = render(UserAvatar, {
|
|
27
|
-
props: { profile, showName: true },
|
|
28
|
-
});
|
|
29
|
-
await expectNoA11yViolations(container);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Component coverage for UserCard via the shared S11 harness (#1416).
|
|
4
|
-
*/
|
|
5
|
-
import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
-
import UserCard from '../UserCard.svelte';
|
|
8
|
-
const baseProps = (over = {}) => ({
|
|
9
|
-
user: { id: 'u1', email: 'ada@example.com', status: 'active' },
|
|
10
|
-
profile: { name: 'Ada Lovelace' },
|
|
11
|
-
role: 'admin',
|
|
12
|
-
status: 'active',
|
|
13
|
-
...over,
|
|
14
|
-
});
|
|
15
|
-
describe('UserCard', () => {
|
|
16
|
-
it('renders the name, email, role, and status', () => {
|
|
17
|
-
render(UserCard, { props: baseProps() });
|
|
18
|
-
expect(screen.getByText('Ada Lovelace')).toBeInTheDocument();
|
|
19
|
-
expect(screen.getByText('ada@example.com')).toBeInTheDocument();
|
|
20
|
-
expect(screen.getByText('admin')).toBeInTheDocument();
|
|
21
|
-
expect(screen.getByText('active')).toBeInTheDocument();
|
|
22
|
-
});
|
|
23
|
-
it('invokes onclick when the card is activated', async () => {
|
|
24
|
-
const onclick = vi.fn();
|
|
25
|
-
render(UserCard, { props: baseProps({ onclick }) });
|
|
26
|
-
await userEvent.click(screen.getByRole('button'));
|
|
27
|
-
expect(onclick).toHaveBeenCalledTimes(1);
|
|
28
|
-
});
|
|
29
|
-
it('is a disabled, non-interactive card without an onclick', () => {
|
|
30
|
-
render(UserCard, { props: baseProps() });
|
|
31
|
-
expect(screen.getByRole('button')).toBeDisabled();
|
|
32
|
-
});
|
|
33
|
-
it('is axe-clean', async () => {
|
|
34
|
-
const { container } = render(UserCard, {
|
|
35
|
-
props: baseProps({ onclick: vi.fn() }),
|
|
36
|
-
});
|
|
37
|
-
await expectNoA11yViolations(container);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Component coverage for UserForm via the shared S11 harness (#1416).
|
|
4
|
-
*/
|
|
5
|
-
import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
-
import UserForm from '../UserForm.svelte';
|
|
8
|
-
describe('UserForm', () => {
|
|
9
|
-
it('renders create-mode fields and a Create button', () => {
|
|
10
|
-
render(UserForm, { props: { onsubmit: vi.fn() } });
|
|
11
|
-
expect(screen.getByLabelText('Name')).toBeInTheDocument();
|
|
12
|
-
expect(screen.getByLabelText('Email')).toBeInTheDocument();
|
|
13
|
-
expect(screen.getByLabelText('Status')).toBeInTheDocument();
|
|
14
|
-
expect(screen.getByRole('button', { name: 'Create User' })).toBeInTheDocument();
|
|
15
|
-
});
|
|
16
|
-
it('submits the entered name and email', async () => {
|
|
17
|
-
const onsubmit = vi.fn();
|
|
18
|
-
render(UserForm, { props: { onsubmit } });
|
|
19
|
-
await userEvent.type(screen.getByLabelText('Name'), 'Ada Lovelace');
|
|
20
|
-
await userEvent.type(screen.getByLabelText('Email'), 'ada@example.com');
|
|
21
|
-
await userEvent.click(screen.getByRole('button', { name: 'Create User' }));
|
|
22
|
-
expect(onsubmit).toHaveBeenCalledWith(expect.objectContaining({
|
|
23
|
-
name: 'Ada Lovelace',
|
|
24
|
-
email: 'ada@example.com',
|
|
25
|
-
}));
|
|
26
|
-
});
|
|
27
|
-
it('locks the email and switches to update mode for an existing user', () => {
|
|
28
|
-
render(UserForm, {
|
|
29
|
-
props: {
|
|
30
|
-
onsubmit: vi.fn(),
|
|
31
|
-
user: { email: 'ada@example.com', status: 'active' },
|
|
32
|
-
profile: { name: 'Ada Lovelace' },
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
expect(screen.getByLabelText('Email')).toBeDisabled();
|
|
36
|
-
expect(screen.getByRole('button', { name: 'Update User' })).toBeInTheDocument();
|
|
37
|
-
});
|
|
38
|
-
it('invokes oncancel from the Cancel button', async () => {
|
|
39
|
-
const oncancel = vi.fn();
|
|
40
|
-
render(UserForm, { props: { onsubmit: vi.fn(), oncancel } });
|
|
41
|
-
await userEvent.click(screen.getByRole('button', { name: 'Cancel' }));
|
|
42
|
-
expect(oncancel).toHaveBeenCalledTimes(1);
|
|
43
|
-
});
|
|
44
|
-
it('is axe-clean', async () => {
|
|
45
|
-
const { container } = render(UserForm, {
|
|
46
|
-
props: { onsubmit: vi.fn(), oncancel: vi.fn() },
|
|
47
|
-
});
|
|
48
|
-
await expectNoA11yViolations(container);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Component coverage for UserList via the shared S11 harness (#1416).
|
|
4
|
-
*/
|
|
5
|
-
import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
-
import UserList from '../UserList.svelte';
|
|
8
|
-
const users = [
|
|
9
|
-
{
|
|
10
|
-
user: { id: 'u1', email: 'ada@example.com', status: 'active' },
|
|
11
|
-
profile: { name: 'Ada Lovelace' },
|
|
12
|
-
role: 'admin',
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
user: { id: 'u2', email: 'alan@example.com', status: 'pending' },
|
|
16
|
-
profile: { name: 'Alan Turing' },
|
|
17
|
-
role: 'member',
|
|
18
|
-
},
|
|
19
|
-
];
|
|
20
|
-
describe('UserList', () => {
|
|
21
|
-
it('renders a card per user', () => {
|
|
22
|
-
render(UserList, { props: { users } });
|
|
23
|
-
expect(screen.getByText('Ada Lovelace')).toBeInTheDocument();
|
|
24
|
-
expect(screen.getByText('Alan Turing')).toBeInTheDocument();
|
|
25
|
-
});
|
|
26
|
-
it('forwards the selected user through onselect', async () => {
|
|
27
|
-
const onselect = vi.fn();
|
|
28
|
-
render(UserList, { props: { users, onselect } });
|
|
29
|
-
await userEvent.click(screen.getByText('Alan Turing'));
|
|
30
|
-
expect(onselect).toHaveBeenCalledWith(expect.objectContaining({ id: 'u2' }));
|
|
31
|
-
});
|
|
32
|
-
it('shows the empty message when there are no users', () => {
|
|
33
|
-
render(UserList, {
|
|
34
|
-
props: { users: [], emptyMessage: 'Nobody here' },
|
|
35
|
-
});
|
|
36
|
-
expect(screen.getByText('Nobody here')).toBeInTheDocument();
|
|
37
|
-
});
|
|
38
|
-
it('shows a loading state', () => {
|
|
39
|
-
render(UserList, { props: { users: [], loading: true } });
|
|
40
|
-
expect(screen.getByText('Loading users...')).toBeInTheDocument();
|
|
41
|
-
});
|
|
42
|
-
it('is axe-clean', async () => {
|
|
43
|
-
const { container } = render(UserList, {
|
|
44
|
-
props: { users, onselect: vi.fn() },
|
|
45
|
-
});
|
|
46
|
-
await expectNoA11yViolations(container);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Component coverage for UserMenu via the shared S11 harness (#1416), plus the
|
|
4
|
-
* S12 a11y remediation (#1417): the open dropdown now has its own id (no longer
|
|
5
|
-
* duplicating the wrapper) and `aria-labelledby` resolves to the trigger, so axe
|
|
6
|
-
* is asserted on both the collapsed and open states.
|
|
7
|
-
*/
|
|
8
|
-
import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
9
|
-
import { describe, expect, it } from 'vitest';
|
|
10
|
-
import UserMenu from '../UserMenu.svelte';
|
|
11
|
-
describe('UserMenu', () => {
|
|
12
|
-
it('renders a collapsed trigger labelled with the display name', () => {
|
|
13
|
-
render(UserMenu, { props: { user: { name: 'Ada Lovelace' } } });
|
|
14
|
-
const trigger = screen.getByRole('button', { name: 'User menu' });
|
|
15
|
-
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
16
|
-
expect(screen.getByText('Ada Lovelace')).toBeInTheDocument();
|
|
17
|
-
expect(screen.queryByRole('menu')).toBeNull();
|
|
18
|
-
});
|
|
19
|
-
it('opens the menu with profile/settings/sign-out items on click', async () => {
|
|
20
|
-
render(UserMenu, {
|
|
21
|
-
props: { user: { name: 'Ada Lovelace', email: 'ada@example.com' } },
|
|
22
|
-
});
|
|
23
|
-
await userEvent.click(screen.getByRole('button', { name: 'User menu' }));
|
|
24
|
-
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
25
|
-
expect(screen.getByRole('menuitem', { name: 'Profile' })).toBeInTheDocument();
|
|
26
|
-
expect(screen.getByRole('menuitem', { name: 'Settings' })).toBeInTheDocument();
|
|
27
|
-
expect(screen.getByRole('menuitem', { name: 'Sign out' })).toBeInTheDocument();
|
|
28
|
-
});
|
|
29
|
-
it('is axe-clean while collapsed and when open', async () => {
|
|
30
|
-
const { container } = render(UserMenu, {
|
|
31
|
-
props: { user: { name: 'Ada Lovelace', email: 'ada@example.com' } },
|
|
32
|
-
});
|
|
33
|
-
await expectNoA11yViolations(container);
|
|
34
|
-
await userEvent.click(screen.getByRole('button', { name: 'User menu' }));
|
|
35
|
-
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
36
|
-
await expectNoA11yViolations(container);
|
|
37
|
-
});
|
|
38
|
-
// Regression for #1399 blocker #1: the menu items were keyboard-unreachable
|
|
39
|
-
// (role="menu" with no roving tabindex / arrow navigation). These assert the
|
|
40
|
-
// WAI-ARIA menu-button keyboard contract end to end.
|
|
41
|
-
const kbProps = {
|
|
42
|
-
user: { name: 'Ada Lovelace', email: 'ada@example.com' },
|
|
43
|
-
};
|
|
44
|
-
it('opens from the trigger and focuses the first item on ArrowDown', async () => {
|
|
45
|
-
render(UserMenu, { props: kbProps });
|
|
46
|
-
screen.getByRole('button', { name: 'User menu' }).focus();
|
|
47
|
-
await userEvent.keyboard('{ArrowDown}');
|
|
48
|
-
const items = screen.getAllByRole('menuitem');
|
|
49
|
-
expect(items).toHaveLength(3);
|
|
50
|
-
expect(document.activeElement).toBe(items[0]);
|
|
51
|
-
});
|
|
52
|
-
it('moves roving focus with ArrowDown/ArrowUp and wraps at the ends', async () => {
|
|
53
|
-
render(UserMenu, { props: kbProps });
|
|
54
|
-
screen.getByRole('button', { name: 'User menu' }).focus();
|
|
55
|
-
await userEvent.keyboard('{ArrowDown}');
|
|
56
|
-
const items = screen.getAllByRole('menuitem');
|
|
57
|
-
await userEvent.keyboard('{ArrowDown}');
|
|
58
|
-
expect(document.activeElement).toBe(items[1]);
|
|
59
|
-
// From the first item, ArrowUp wraps to the last.
|
|
60
|
-
await userEvent.keyboard('{ArrowUp}{ArrowUp}');
|
|
61
|
-
expect(document.activeElement).toBe(items[items.length - 1]);
|
|
62
|
-
});
|
|
63
|
-
it('jumps to the last item with End and the first with Home', async () => {
|
|
64
|
-
render(UserMenu, { props: kbProps });
|
|
65
|
-
screen.getByRole('button', { name: 'User menu' }).focus();
|
|
66
|
-
await userEvent.keyboard('{ArrowDown}');
|
|
67
|
-
const items = screen.getAllByRole('menuitem');
|
|
68
|
-
await userEvent.keyboard('{End}');
|
|
69
|
-
expect(document.activeElement).toBe(items[items.length - 1]);
|
|
70
|
-
await userEvent.keyboard('{Home}');
|
|
71
|
-
expect(document.activeElement).toBe(items[0]);
|
|
72
|
-
});
|
|
73
|
-
it('closes on Escape and restores focus to the trigger', async () => {
|
|
74
|
-
render(UserMenu, { props: kbProps });
|
|
75
|
-
const trigger = screen.getByRole('button', { name: 'User menu' });
|
|
76
|
-
trigger.focus();
|
|
77
|
-
await userEvent.keyboard('{ArrowDown}');
|
|
78
|
-
expect(screen.queryByRole('menu')).not.toBeNull();
|
|
79
|
-
await userEvent.keyboard('{Escape}');
|
|
80
|
-
expect(screen.queryByRole('menu')).toBeNull();
|
|
81
|
-
expect(document.activeElement).toBe(trigger);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { UserStatus } from '@happyvertical/smrt-types';
|
|
2
|
-
import { render, screen } from '@happyvertical/smrt-vitest/svelte';
|
|
3
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
-
import UserCard from '../UserCard.svelte';
|
|
5
|
-
import UserForm from '../UserForm.svelte';
|
|
6
|
-
const profile = { name: 'Ada Lovelace', email: 'ada@example.com' };
|
|
7
|
-
const user = { email: 'ada@example.com', status: UserStatus.INACTIVE };
|
|
8
|
-
describe('UserForm status options', () => {
|
|
9
|
-
it('offers exactly the UserStatus values — including inactive, never deactivated', () => {
|
|
10
|
-
render(UserForm, { props: { onsubmit: vi.fn() } });
|
|
11
|
-
const select = screen.getByLabelText('Status', {
|
|
12
|
-
hidden: true,
|
|
13
|
-
});
|
|
14
|
-
const optionValues = Array.from(select.options).map((o) => o.value);
|
|
15
|
-
expect(optionValues).toEqual(Object.values(UserStatus));
|
|
16
|
-
expect(optionValues).toContain('inactive');
|
|
17
|
-
expect(optionValues).not.toContain('deactivated');
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
describe('UserCard status styling', () => {
|
|
21
|
-
it('styles an inactive user instead of leaving it unstyled', () => {
|
|
22
|
-
render(UserCard, {
|
|
23
|
-
props: { user, profile, status: 'inactive' },
|
|
24
|
-
});
|
|
25
|
-
const badge = screen.getByText('inactive', { hidden: true });
|
|
26
|
-
expect(badge.className).toContain('status-disabled');
|
|
27
|
-
});
|
|
28
|
-
it('does not recognise the bogus deactivated value', () => {
|
|
29
|
-
render(UserCard, {
|
|
30
|
-
props: { user, profile, status: 'deactivated' },
|
|
31
|
-
});
|
|
32
|
-
const badge = screen.getByText('deactivated', { hidden: true });
|
|
33
|
-
// No status-* style class is applied for a non-enum value.
|
|
34
|
-
expect(badge.className).not.toContain('status-disabled');
|
|
35
|
-
});
|
|
36
|
-
});
|