beads-ui 0.1.0 → 0.1.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.
Files changed (57) hide show
  1. package/CHANGES.md +8 -0
  2. package/README.md +7 -3
  3. package/package.json +12 -2
  4. package/.beads/issues.jsonl +0 -107
  5. package/.editorconfig +0 -10
  6. package/.eslintrc.json +0 -36
  7. package/.github/workflows/ci.yml +0 -38
  8. package/.prettierignore +0 -5
  9. package/AGENTS.md +0 -85
  10. package/app/data/providers.test.js +0 -126
  11. package/app/main.board-switch.test.js +0 -94
  12. package/app/main.deep-link.test.js +0 -64
  13. package/app/main.live-updates.test.js +0 -229
  14. package/app/main.test.js +0 -17
  15. package/app/main.theme.test.js +0 -41
  16. package/app/main.view-sync.test.js +0 -54
  17. package/app/protocol.test.js +0 -57
  18. package/app/router.test.js +0 -34
  19. package/app/state.test.js +0 -21
  20. package/app/utils/markdown.test.js +0 -103
  21. package/app/utils/type-badge.test.js +0 -30
  22. package/app/views/board.test.js +0 -184
  23. package/app/views/detail.acceptance-notes.test.js +0 -67
  24. package/app/views/detail.assignee.test.js +0 -161
  25. package/app/views/detail.deps.test.js +0 -97
  26. package/app/views/detail.edits.test.js +0 -146
  27. package/app/views/detail.labels.test.js +0 -73
  28. package/app/views/detail.priority.test.js +0 -86
  29. package/app/views/detail.test.js +0 -188
  30. package/app/views/detail.ui47.test.js +0 -78
  31. package/app/views/epics.test.js +0 -283
  32. package/app/views/list.inline-edits.test.js +0 -84
  33. package/app/views/list.test.js +0 -479
  34. package/app/views/nav.test.js +0 -43
  35. package/app/ws.test.js +0 -168
  36. package/eslint.config.js +0 -59
  37. package/media/bdui-board.png +0 -0
  38. package/media/bdui-epics.png +0 -0
  39. package/media/bdui-issues.png +0 -0
  40. package/prettier.config.js +0 -13
  41. package/server/app.test.js +0 -29
  42. package/server/bd.test.js +0 -93
  43. package/server/cli/cli.test.js +0 -109
  44. package/server/cli/commands.integration.test.js +0 -155
  45. package/server/cli/commands.unit.test.js +0 -94
  46. package/server/cli/open.test.js +0 -26
  47. package/server/db.test.js +0 -70
  48. package/server/protocol.test.js +0 -87
  49. package/server/watcher.test.js +0 -100
  50. package/server/ws.handlers.test.js +0 -174
  51. package/server/ws.labels.test.js +0 -95
  52. package/server/ws.mutations.test.js +0 -261
  53. package/server/ws.subscriptions.test.js +0 -116
  54. package/server/ws.test.js +0 -52
  55. package/test/setup-vitest.js +0 -12
  56. package/tsconfig.json +0 -23
  57. package/vitest.config.mjs +0 -14
@@ -1,41 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
-
3
- describe('theme toggle', () => {
4
- test('sets dark data-theme and persists preference', async () => {
5
- document.body.innerHTML = `
6
- <header class="app-header">
7
- <h1 class="app-title">beads-ui</h1>
8
- <div class="header-actions">
9
- <label class="theme-toggle">
10
- <span>Dark</span>
11
- <input id="theme-switch" type="checkbox" />
12
- </label>
13
- </div>
14
- </header>
15
- <main id="app"></main>`;
16
-
17
- // Simulate the DOMContentLoaded logic from main.js
18
- const themeSwitch = /** @type {HTMLInputElement} */ (
19
- document.getElementById('theme-switch')
20
- );
21
- themeSwitch.checked = true;
22
- themeSwitch.dispatchEvent(new Event('change'));
23
-
24
- // Apply attribute as in main.js handler
25
- document.documentElement.setAttribute('data-theme', 'dark');
26
- window.localStorage.setItem('beads-ui.theme', 'dark');
27
-
28
- expect(document.documentElement.getAttribute('data-theme')).toBe('dark');
29
- expect(window.localStorage.getItem('beads-ui.theme')).toBe('dark');
30
- });
31
-
32
- test('can switch back to light explicitly', async () => {
33
- document.documentElement.setAttribute('data-theme', 'dark');
34
- window.localStorage.setItem('beads-ui.theme', 'dark');
35
- // Simulate toggle off
36
- document.documentElement.setAttribute('data-theme', 'light');
37
- window.localStorage.setItem('beads-ui.theme', 'light');
38
- expect(document.documentElement.getAttribute('data-theme')).toBe('light');
39
- expect(window.localStorage.getItem('beads-ui.theme')).toBe('light');
40
- });
41
- });
@@ -1,54 +0,0 @@
1
- import { describe, expect, test, vi } from 'vitest';
2
- import { bootstrap } from './main.js';
3
-
4
- // Mock WS client before importing the app
5
- vi.mock('./ws.js', () => ({
6
- createWsClient: () => ({
7
- /**
8
- * @param {string} type
9
- */
10
- async send(type) {
11
- // Return minimal data for the list view
12
- if (type === 'list-issues') {
13
- return [];
14
- }
15
- if (type === 'show-issue') {
16
- return null;
17
- }
18
- if (type === 'epic-status') {
19
- return [];
20
- }
21
- return null;
22
- },
23
- on() {
24
- return () => {};
25
- },
26
- close() {},
27
- getState() {
28
- return 'open';
29
- }
30
- })
31
- }));
32
-
33
- describe('initial view sync on reload (#/epics)', () => {
34
- test('shows Epics view when hash is #/epics', async () => {
35
- window.location.hash = '#/epics';
36
- document.body.innerHTML = '<main id="app"></main>';
37
- const root = /** @type {HTMLElement} */ (document.getElementById('app'));
38
-
39
- bootstrap(root);
40
-
41
- // Allow any microtasks to flush
42
- await Promise.resolve();
43
-
44
- const issuesRoot = /** @type {HTMLElement} */ (
45
- document.getElementById('issues-root')
46
- );
47
- const epicsRoot = /** @type {HTMLElement} */ (
48
- document.getElementById('epics-root')
49
- );
50
-
51
- expect(issuesRoot.hidden).toBe(true);
52
- expect(epicsRoot.hidden).toBe(false);
53
- });
54
- });
@@ -1,57 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import {
3
- MESSAGE_TYPES,
4
- PROTOCOL_VERSION,
5
- decodeReply,
6
- decodeRequest,
7
- isMessageType,
8
- isReply,
9
- isRequest,
10
- makeError,
11
- makeOk,
12
- makeRequest
13
- } from './protocol.js';
14
-
15
- describe('protocol', () => {
16
- test('version and message types', () => {
17
- expect(typeof PROTOCOL_VERSION).toBe('string');
18
- expect(Array.isArray(MESSAGE_TYPES)).toBe(true);
19
- expect(MESSAGE_TYPES.length).toBeGreaterThan(3);
20
- expect(isMessageType('list-issues')).toBe(true);
21
- expect(isMessageType('unknown-type')).toBe(false);
22
- });
23
-
24
- test('makeRequest / isRequest / decodeRequest', () => {
25
- const req = makeRequest(
26
- 'list-issues',
27
- { filters: { status: 'open' } },
28
- 'r-1'
29
- );
30
- expect(isRequest(req)).toBe(true);
31
- const round = decodeRequest(JSON.parse(JSON.stringify(req)));
32
- expect(round.id).toBe('r-1');
33
- expect(round.type).toBe('list-issues');
34
- });
35
-
36
- test('makeOk / makeError / isReply / decodeReply', () => {
37
- const req = makeRequest('show-issue', { id: 'UI-1' }, 'r-2');
38
- const ok = makeOk(req, { id: 'UI-1', title: 'T' });
39
- expect(isReply(ok)).toBe(true);
40
- const ok2 = decodeReply(JSON.parse(JSON.stringify(ok)));
41
- expect(ok2.ok).toBe(true);
42
-
43
- const err = makeError(req, 'not_found', 'Issue not found');
44
- expect(isReply(err)).toBe(true);
45
- const err2 = decodeReply(JSON.parse(JSON.stringify(err)));
46
- expect(err2.ok).toBe(false);
47
- if (!('error' in err2) || !err2.error) {
48
- throw new Error('Expected error to be present when ok=false');
49
- }
50
- expect(err2.error.code).toBe('not_found');
51
- });
52
-
53
- test('invalid envelopes are rejected', () => {
54
- expect(() => decodeRequest({})).toThrow();
55
- expect(() => decodeReply({ ok: true })).toThrow();
56
- });
57
- });
@@ -1,34 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import { createHashRouter, parseHash, parseView } from './router.js';
3
- import { createStore } from './state.js';
4
-
5
- describe('router', () => {
6
- test('parseHash extracts id', () => {
7
- expect(parseHash('#/issue/UI-5')).toBe('UI-5');
8
- expect(parseHash('#/anything')).toBeNull();
9
- });
10
-
11
- test('router updates store and gotoIssue updates hash', () => {
12
- document.body.innerHTML = '<div></div>';
13
- const store = createStore();
14
- const router = createHashRouter(store);
15
- router.start();
16
-
17
- window.location.hash = '#/issue/UI-10';
18
- // Trigger handler synchronously
19
- window.dispatchEvent(new HashChangeEvent('hashchange'));
20
- expect(store.getState().selected_id).toBe('UI-10');
21
-
22
- router.gotoIssue('UI-11');
23
- expect(window.location.hash).toBe('#/issue/UI-11');
24
- router.stop();
25
- });
26
-
27
- test('parseView resolves from hash and defaults to issues', () => {
28
- expect(parseView('#/issues')).toBe('issues');
29
- expect(parseView('#/epics')).toBe('epics');
30
- expect(parseView('#/board')).toBe('board');
31
- expect(parseView('')).toBe('issues');
32
- expect(parseView('#/unknown')).toBe('issues');
33
- });
34
- });
package/app/state.test.js DELETED
@@ -1,21 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import { createStore } from './state.js';
3
-
4
- describe('state store', () => {
5
- test('get/set/subscribe works and dedupes unchanged', () => {
6
- const store = createStore();
7
- const seen = [];
8
- const off = store.subscribe((s) => seen.push(s));
9
-
10
- store.setState({ selected_id: 'UI-1' });
11
- store.setState({ filters: { status: 'open' } });
12
- // no-op (unchanged)
13
- store.setState({ filters: { status: 'open' } });
14
- off();
15
-
16
- expect(seen.length).toBe(2);
17
- const state = store.getState();
18
- expect(state.selected_id).toBe('UI-1');
19
- expect(state.filters.status).toBe('open');
20
- });
21
- });
@@ -1,103 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import { renderMarkdown } from './markdown.js';
3
-
4
- describe('utils/markdown', () => {
5
- test('returns fragment for empty input', () => {
6
- const frag = renderMarkdown('');
7
-
8
- expect(frag).toBeInstanceOf(DocumentFragment);
9
- });
10
-
11
- test('renders headings', () => {
12
- const frag = renderMarkdown('# Title\n\n### Sub');
13
- const host = document.createElement('div');
14
-
15
- host.appendChild(frag);
16
-
17
- const h1 = /** @type {HTMLHeadingElement} */ (host.querySelector('h1'));
18
- const h3 = /** @type {HTMLHeadingElement} */ (host.querySelector('h3'));
19
- expect(h1.textContent).toBe('Title');
20
- expect(h3.textContent).toBe('Sub');
21
- });
22
-
23
- test('renders paragraphs with and without blank lines', () => {
24
- const frag = renderMarkdown('First line\ncontinues\n\nSecond para');
25
- const host = document.createElement('div');
26
-
27
- host.appendChild(frag);
28
-
29
- const ps = host.querySelectorAll('p');
30
- expect(ps.length).toBe(2);
31
- expect(ps[0].textContent).toBe('First line continues');
32
- expect(ps[1].textContent).toBe('Second para');
33
- });
34
-
35
- test('renders unordered list items', () => {
36
- const frag = renderMarkdown('- a\n- b');
37
- const host = document.createElement('div');
38
-
39
- host.appendChild(frag);
40
-
41
- const items = host.querySelectorAll('ul li');
42
- expect(items.length).toBe(2);
43
- expect(items[0].textContent).toBe('a');
44
- expect(items[1].textContent).toBe('b');
45
- });
46
-
47
- test('renders ordered list items', () => {
48
- const frag = renderMarkdown('1. a\n2. b');
49
- const host = document.createElement('div');
50
-
51
- host.appendChild(frag);
52
-
53
- const items = host.querySelectorAll('ol li');
54
- expect(items.length).toBe(2);
55
- expect(items[0].textContent).toBe('a');
56
- expect(items[1].textContent).toBe('b');
57
- });
58
-
59
- test('renders fenced code block', () => {
60
- const frag = renderMarkdown('```\nline1\nline2\n```');
61
- const host = document.createElement('div');
62
-
63
- host.appendChild(frag);
64
-
65
- const code = /** @type {HTMLElement} */ (host.querySelector('pre > code'));
66
- expect(code.textContent).toBe('line1\nline2');
67
- });
68
-
69
- test('renders inline code', () => {
70
- const frag = renderMarkdown('text `code` end');
71
- const host = document.createElement('div');
72
-
73
- host.appendChild(frag);
74
-
75
- const code = /** @type {HTMLElement} */ (host.querySelector('p code'));
76
- expect(code.textContent).toBe('code');
77
- });
78
-
79
- test('renders http and mailto links', () => {
80
- const frag = renderMarkdown(
81
- '[web](https://example.com) and [mail](mailto:test@example.com)'
82
- );
83
- const host = document.createElement('div');
84
-
85
- host.appendChild(frag);
86
-
87
- const hrefs = Array.from(host.querySelectorAll('a')).map((a) =>
88
- a.getAttribute('href')
89
- );
90
- expect(hrefs).toEqual(['https://example.com', 'mailto:test@example.com']);
91
- });
92
-
93
- test('filters unsafe link schemes', () => {
94
- const frag = renderMarkdown('x [danger](javascript:alert(1)) y');
95
- const host = document.createElement('div');
96
-
97
- host.appendChild(frag);
98
-
99
- const anchors = host.querySelectorAll('a');
100
- expect(anchors.length).toBe(0);
101
- expect(host.textContent || '').toContain('danger (javascript:alert(1))');
102
- });
103
- });
@@ -1,30 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import { createTypeBadge } from './type-badge.js';
3
-
4
- describe('utils/type-badge', () => {
5
- test('renders known types with modifier class and accessible labels', () => {
6
- const types = [
7
- ['bug', 'Bug'],
8
- ['feature', 'Feature'],
9
- ['task', 'Task'],
10
- ['epic', 'Epic'],
11
- ['chore', 'Chore']
12
- ];
13
- for (const [t, label] of /** @type {any[]} */ (types)) {
14
- const el = createTypeBadge(t);
15
- expect(el.classList.contains('type-badge')).toBe(true);
16
- expect(el.classList.contains(`type-badge--${t}`)).toBe(true);
17
- expect(el.getAttribute('role')).toBe('img');
18
- const aria = el.getAttribute('aria-label') || '';
19
- expect(aria.toLowerCase()).toContain('issue type');
20
- expect(aria).toContain(label);
21
- expect(el.textContent).toBe(label);
22
- }
23
- });
24
-
25
- test('falls back to neutral for unknown types', () => {
26
- const el = createTypeBadge('unknown');
27
- expect(el.classList.contains('type-badge--neutral')).toBe(true);
28
- expect(el.textContent).toBe('—');
29
- });
30
- });
@@ -1,184 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import { createBoardView } from './board.js';
3
-
4
- describe('views/board', () => {
5
- test('renders four columns with sorted cards and navigates on click', async () => {
6
- document.body.innerHTML = '<div id="m"></div>';
7
- const mount = /** @type {HTMLElement} */ (document.getElementById('m'));
8
-
9
- /** @type {{ getOpen: () => Promise<any[]>, getReady: () => Promise<any[]>, getInProgress: () => Promise<any[]>, getClosed: () => Promise<any[]> }} */
10
- const data = {
11
- async getOpen() {
12
- return [
13
- {
14
- id: 'O-1',
15
- title: 'o1',
16
- updated_at: '2025-10-23T07:00:00.000Z',
17
- issue_type: 'task'
18
- },
19
- {
20
- id: 'R-2', // also present in Ready, should be filtered from Open
21
- title: 'dup-ready',
22
- updated_at: '2025-10-22T07:00:00.000Z',
23
- issue_type: 'task'
24
- }
25
- ];
26
- },
27
- async getReady() {
28
- return [
29
- {
30
- id: 'R-2',
31
- title: 'r2',
32
- priority: 1,
33
- updated_at: '2025-10-20T08:00:00.000Z',
34
- issue_type: 'task'
35
- },
36
- {
37
- id: 'R-1',
38
- title: 'r1',
39
- priority: 0,
40
- updated_at: '2025-10-21T08:00:00.000Z',
41
- issue_type: 'bug'
42
- },
43
- {
44
- id: 'R-3',
45
- title: 'r3',
46
- priority: 1,
47
- updated_at: '2025-10-22T08:00:00.000Z',
48
- issue_type: 'feature'
49
- }
50
- ];
51
- },
52
- async getInProgress() {
53
- return [
54
- {
55
- id: 'P-1',
56
- title: 'p1',
57
- updated_at: '2025-10-23T09:00:00.000Z',
58
- issue_type: 'task'
59
- },
60
- {
61
- id: 'P-2',
62
- title: 'p2',
63
- updated_at: '2025-10-22T09:00:00.000Z',
64
- issue_type: 'feature'
65
- }
66
- ];
67
- },
68
- async getClosed() {
69
- return [
70
- {
71
- id: 'C-2',
72
- title: 'c2',
73
- updated_at: '2025-10-20T09:00:00.000Z',
74
- issue_type: 'task'
75
- },
76
- {
77
- id: 'C-1',
78
- title: 'c1',
79
- updated_at: '2025-10-21T09:00:00.000Z',
80
- issue_type: 'bug'
81
- }
82
- ];
83
- }
84
- };
85
-
86
- /** @type {string[]} */
87
- const navigations = [];
88
- const view = createBoardView(mount, /** @type {any} */ (data), (id) => {
89
- navigations.push(id);
90
- });
91
-
92
- await view.load();
93
-
94
- // Open: updated_at desc; excludes items present in Ready
95
- const open_ids = Array.from(
96
- mount.querySelectorAll('#open-col .board-card .mono')
97
- ).map((el) => el.textContent?.trim());
98
- expect(open_ids).toEqual(['#1']);
99
-
100
- // Ready: priority asc, then updated_at desc for equal priority
101
- const ready_ids = Array.from(
102
- mount.querySelectorAll('#ready-col .board-card .mono')
103
- ).map((el) => el.textContent?.trim());
104
- expect(ready_ids).toEqual(['#1', '#3', '#2']);
105
-
106
- // In progress: updated_at desc
107
- const prog_ids = Array.from(
108
- mount.querySelectorAll('#in-progress-col .board-card .mono')
109
- ).map((el) => el.textContent?.trim());
110
- expect(prog_ids).toEqual(['#1', '#2']);
111
-
112
- // Closed: updated_at desc
113
- const closed_ids = Array.from(
114
- mount.querySelectorAll('#closed-col .board-card .mono')
115
- ).map((el) => el.textContent?.trim());
116
- expect(closed_ids).toEqual(['#1', '#2']);
117
-
118
- // Click navigates
119
- const first_ready = /** @type {HTMLElement|null} */ (
120
- mount.querySelector('#ready-col .board-card')
121
- );
122
- first_ready?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
123
- expect(navigations[0]).toBe('R-1');
124
- });
125
-
126
- test('filters Ready to exclude items that are In Progress', async () => {
127
- document.body.innerHTML = '<div id="m"></div>';
128
- const mount = /** @type {HTMLElement} */ (document.getElementById('m'));
129
-
130
- /** @type {{ getOpen: () => Promise<any[]>, getReady: () => Promise<any[]>, getInProgress: () => Promise<any[]>, getClosed: () => Promise<any[]> }} */
131
- const data = {
132
- async getOpen() {
133
- return [];
134
- },
135
- async getReady() {
136
- return [
137
- {
138
- id: 'X-1',
139
- title: 'x1',
140
- priority: 1,
141
- updated_at: '2025-10-23T10:00:00.000Z',
142
- issue_type: 'task'
143
- },
144
- {
145
- id: 'X-2',
146
- title: 'x2',
147
- priority: 1,
148
- updated_at: '2025-10-23T09:00:00.000Z',
149
- issue_type: 'task'
150
- }
151
- ];
152
- },
153
- async getInProgress() {
154
- return [
155
- {
156
- id: 'X-2',
157
- title: 'x2',
158
- updated_at: '2025-10-23T11:00:00.000Z',
159
- issue_type: 'task'
160
- }
161
- ];
162
- },
163
- async getClosed() {
164
- return [];
165
- }
166
- };
167
-
168
- const view = createBoardView(mount, /** @type {any} */ (data), () => {});
169
-
170
- await view.load();
171
-
172
- const ready_ids = Array.from(
173
- mount.querySelectorAll('#ready-col .board-card .mono')
174
- ).map((el) => el.textContent?.trim());
175
-
176
- // X-2 is in progress, so Ready should only show X-1
177
- expect(ready_ids).toEqual(['#1']);
178
-
179
- const prog_ids = Array.from(
180
- mount.querySelectorAll('#in-progress-col .board-card .mono')
181
- ).map((el) => el.textContent?.trim());
182
- expect(prog_ids).toEqual(['#2']);
183
- });
184
- });
@@ -1,67 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import { createDetailView } from './detail.js';
3
-
4
- /** @type {(map: Record<string, any>) => (type: string, payload?: unknown) => Promise<any>} */
5
- const stubSend = (map) => async (type, payload) => {
6
- if (type !== 'show-issue') {
7
- throw new Error('Unexpected type');
8
- }
9
- const id = /** @type {any} */ (payload).id;
10
- return map[id] || null;
11
- };
12
-
13
- describe('views/detail acceptance + notes', () => {
14
- test('renders acceptance from acceptance_criteria and notes markdown', async () => {
15
- document.body.innerHTML =
16
- '<section class="panel"><div id="mount"></div></section>';
17
- const mount = /** @type {HTMLElement} */ (document.getElementById('mount'));
18
-
19
- /** @type {any} */
20
- const issue = {
21
- id: 'UI-71',
22
- title: 'Has acceptance + notes',
23
- acceptance_criteria: '- step A\n- step B',
24
- notes: 'Plain note text',
25
- status: 'open',
26
- priority: 2
27
- };
28
-
29
- const view = createDetailView(mount, stubSend({ 'UI-71': issue }));
30
- await view.load('UI-71');
31
-
32
- const accTitle = mount.querySelector('.acceptance .props-card__title');
33
- expect(accTitle && accTitle.textContent).toBe('Acceptance');
34
- const accMd = mount.querySelector('.acceptance .md');
35
- expect(accMd && (accMd.textContent || '').toLowerCase()).toContain(
36
- 'step a'
37
- );
38
-
39
- const notesTitle = mount.querySelector('.notes .props-card__title');
40
- expect(notesTitle && notesTitle.textContent).toBe('Notes');
41
- const notesMd = mount.querySelector('.notes .md');
42
- expect(notesMd && (notesMd.textContent || '')).toContain('Plain note text');
43
- });
44
-
45
- test('gates headings when acceptance and notes are empty', async () => {
46
- document.body.innerHTML =
47
- '<section class="panel"><div id="mount"></div></section>';
48
- const mount = /** @type {HTMLElement} */ (document.getElementById('mount'));
49
-
50
- /** @type {any} */
51
- const issue = {
52
- id: 'UI-72',
53
- title: 'No acceptance/notes',
54
- acceptance_criteria: '',
55
- notes: '',
56
- status: 'open',
57
- priority: 2
58
- };
59
-
60
- const view = createDetailView(mount, stubSend({ 'UI-72': issue }));
61
- await view.load('UI-72');
62
-
63
- // Headings should not be present
64
- expect(mount.querySelector('.acceptance .props-card__title')).toBeNull();
65
- expect(mount.querySelector('.notes .props-card__title')).toBeNull();
66
- });
67
- });