@pie-lib/editable-html-tip-tap 1.1.0-next.6059 → 1.1.1-next.1
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/CHANGELOG.md +44 -0
- package/lib/__tests__/EditableHtml.test.js +374 -0
- package/lib/__tests__/constants.test.js +28 -0
- package/lib/__tests__/extensions.test.js +214 -0
- package/lib/__tests__/index.test.js +246 -0
- package/lib/__tests__/size-utils.test.js +57 -0
- package/lib/__tests__/theme.test.js +17 -0
- package/lib/components/CharacterPicker.js +18 -0
- package/lib/components/CharacterPicker.js.map +1 -1
- package/lib/components/EditableHtml.js +22 -5
- package/lib/components/EditableHtml.js.map +1 -1
- package/lib/components/MenuBar.js +17 -0
- package/lib/components/MenuBar.js.map +1 -1
- package/lib/components/TiptapContainer.js +16 -0
- package/lib/components/TiptapContainer.js.map +1 -1
- package/lib/components/__tests__/AltDialog.test.js +201 -0
- package/lib/components/__tests__/CharacterPicker.test.js +313 -0
- package/lib/components/__tests__/CssIcon.test.js +58 -0
- package/lib/components/__tests__/DragInTheBlank.test.js +309 -0
- package/lib/components/__tests__/ExplicitConstructedResponse.test.js +263 -0
- package/lib/components/__tests__/ImageToolbar.test.js +195 -0
- package/lib/components/__tests__/InlineDropdown.test.js +297 -0
- package/lib/components/__tests__/InsertImageHandler.test.js +162 -0
- package/lib/components/__tests__/MediaDialog.test.js +435 -0
- package/lib/components/__tests__/MediaToolbar.test.js +126 -0
- package/lib/components/__tests__/MediaWrapper.test.js +96 -0
- package/lib/components/__tests__/MenuBar.test.js +459 -0
- package/lib/components/__tests__/RespArea.test.js +171 -0
- package/lib/components/__tests__/TableIcons.test.js +153 -0
- package/lib/components/__tests__/TextAlign.test.js +216 -0
- package/lib/components/__tests__/TiptapContainer.test.js +196 -0
- package/lib/components/__tests__/characterUtils.test.js +189 -0
- package/lib/components/__tests__/choice.test.js +213 -0
- package/lib/components/__tests__/custom-popper.test.js +108 -0
- package/lib/components/__tests__/done-button.test.js +72 -0
- package/lib/components/__tests__/toolbar-buttons.test.js +277 -0
- package/lib/components/characters/characterUtils.js +2 -0
- package/lib/components/characters/characterUtils.js.map +1 -1
- package/lib/components/characters/custom-popper.js +1 -0
- package/lib/components/characters/custom-popper.js.map +1 -1
- package/lib/components/common/done-button.js +1 -0
- package/lib/components/common/done-button.js.map +1 -1
- package/lib/components/common/toolbar-buttons.js +12 -0
- package/lib/components/common/toolbar-buttons.js.map +1 -1
- package/lib/components/icons/CssIcon.js +1 -0
- package/lib/components/icons/CssIcon.js.map +1 -1
- package/lib/components/icons/RespArea.js +10 -0
- package/lib/components/icons/RespArea.js.map +1 -1
- package/lib/components/icons/TableIcons.js +1 -0
- package/lib/components/icons/TableIcons.js.map +1 -1
- package/lib/components/icons/TextAlign.js +7 -0
- package/lib/components/icons/TextAlign.js.map +1 -1
- package/lib/components/image/AltDialog.js +5 -0
- package/lib/components/image/AltDialog.js.map +1 -1
- package/lib/components/image/ImageToolbar.js +13 -0
- package/lib/components/image/ImageToolbar.js.map +1 -1
- package/lib/components/image/InsertImageHandler.js +10 -0
- package/lib/components/image/InsertImageHandler.js.map +1 -1
- package/lib/components/media/MediaDialog.js +18 -0
- package/lib/components/media/MediaDialog.js.map +1 -1
- package/lib/components/media/MediaToolbar.js +2 -0
- package/lib/components/media/MediaToolbar.js.map +1 -1
- package/lib/components/media/MediaWrapper.js +11 -0
- package/lib/components/media/MediaWrapper.js.map +1 -1
- package/lib/components/respArea/DragInTheBlank/DragInTheBlank.js +10 -0
- package/lib/components/respArea/DragInTheBlank/DragInTheBlank.js.map +1 -1
- package/lib/components/respArea/DragInTheBlank/choice.js +8 -0
- package/lib/components/respArea/DragInTheBlank/choice.js.map +1 -1
- package/lib/components/respArea/ExplicitConstructedResponse.js +8 -0
- package/lib/components/respArea/ExplicitConstructedResponse.js.map +1 -1
- package/lib/components/respArea/InlineDropdown.js +7 -0
- package/lib/components/respArea/InlineDropdown.js.map +1 -1
- package/lib/components/respArea/ToolbarIcon.js +10 -0
- package/lib/components/respArea/ToolbarIcon.js.map +1 -1
- package/lib/constants.js +1 -0
- package/lib/constants.js.map +1 -1
- package/lib/extensions/__tests__/component.test.js +314 -0
- package/lib/extensions/__tests__/css.test.js +218 -0
- package/lib/extensions/__tests__/custom-toolbar-wrapper.test.js +185 -0
- package/lib/extensions/__tests__/extended-table.test.js +114 -0
- package/lib/extensions/__tests__/image.test.js +178 -0
- package/lib/extensions/__tests__/media.test.js +296 -0
- package/lib/extensions/__tests__/responseArea.test.js +332 -0
- package/lib/extensions/component.js +22 -2
- package/lib/extensions/css.js +11 -0
- package/lib/extensions/css.js.map +1 -1
- package/lib/extensions/custom-toolbar-wrapper.js +15 -0
- package/lib/extensions/custom-toolbar-wrapper.js.map +1 -1
- package/lib/extensions/extended-table.js +4 -0
- package/lib/extensions/extended-table.js.map +1 -1
- package/lib/extensions/image-component.js +314 -0
- package/lib/extensions/image-component.js.map +1 -0
- package/lib/extensions/image.js +13 -2
- package/lib/extensions/image.js.map +1 -1
- package/lib/extensions/index.js +12 -2
- package/lib/extensions/index.js.map +1 -1
- package/lib/extensions/math.js +16 -0
- package/lib/extensions/math.js.map +1 -1
- package/lib/extensions/media.js +15 -0
- package/lib/extensions/media.js.map +1 -1
- package/lib/extensions/responseArea.js +22 -0
- package/lib/extensions/responseArea.js.map +1 -1
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -1
- package/lib/styles/editorContainerStyles.js +1 -0
- package/lib/styles/editorContainerStyles.js.map +1 -1
- package/lib/theme.js +1 -0
- package/lib/theme.js.map +1 -1
- package/lib/utils/size.js +6 -0
- package/lib/utils/size.js.map +1 -1
- package/package.json +8 -8
- package/src/__tests__/EditableHtml.test.jsx +266 -0
- package/src/__tests__/constants.test.js +20 -0
- package/src/__tests__/extensions.test.js +208 -0
- package/src/__tests__/index.test.jsx +146 -0
- package/src/__tests__/size-utils.test.js +64 -0
- package/src/__tests__/theme.test.js +17 -0
- package/src/components/EditableHtml.jsx +8 -6
- package/src/components/__tests__/AltDialog.test.jsx +147 -0
- package/src/components/__tests__/CharacterPicker.test.jsx +195 -0
- package/src/components/__tests__/CssIcon.test.jsx +46 -0
- package/src/components/__tests__/DragInTheBlank.test.jsx +255 -0
- package/src/components/__tests__/ExplicitConstructedResponse.test.jsx +161 -0
- package/src/components/__tests__/ImageToolbar.test.jsx +128 -0
- package/src/components/__tests__/InlineDropdown.test.jsx +187 -0
- package/src/components/__tests__/InsertImageHandler.test.js +154 -0
- package/src/components/__tests__/MediaDialog.test.jsx +293 -0
- package/src/components/__tests__/MediaToolbar.test.jsx +74 -0
- package/src/components/__tests__/MediaWrapper.test.jsx +81 -0
- package/src/components/__tests__/MenuBar.test.jsx +217 -0
- package/src/components/__tests__/RespArea.test.jsx +122 -0
- package/src/components/__tests__/TableIcons.test.jsx +149 -0
- package/src/components/__tests__/TextAlign.test.jsx +167 -0
- package/src/components/__tests__/TiptapContainer.test.jsx +138 -0
- package/src/components/__tests__/characterUtils.test.js +166 -0
- package/src/components/__tests__/choice.test.jsx +171 -0
- package/src/components/__tests__/custom-popper.test.jsx +82 -0
- package/src/components/__tests__/done-button.test.jsx +54 -0
- package/src/components/__tests__/toolbar-buttons.test.jsx +234 -0
- package/src/extensions/__tests__/css.test.js +196 -0
- package/src/extensions/__tests__/custom-toolbar-wrapper.test.jsx +180 -0
- package/src/extensions/__tests__/extended-table.test.js +107 -0
- package/src/extensions/__tests__/image-component.test.jsx +249 -0
- package/src/extensions/__tests__/image.test.js +136 -0
- package/src/extensions/__tests__/media.test.js +270 -0
- package/src/extensions/__tests__/responseArea.test.js +310 -0
- package/src/extensions/{component.jsx → image-component.jsx} +11 -1
- package/src/extensions/image.js +1 -1
- package/src/extensions/index.js +5 -1
- package/LICENSE.md +0 -5
- package/NEXT.CHANGELOG.json +0 -1
- package/lib/extensions/component.js.map +0 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
|
3
|
+
import MediaToolbar from '../media/MediaToolbar';
|
|
4
|
+
|
|
5
|
+
describe('MediaToolbar', () => {
|
|
6
|
+
it('renders without crashing', () => {
|
|
7
|
+
const { container } = render(<MediaToolbar onEdit={jest.fn()} onRemove={jest.fn()} />);
|
|
8
|
+
expect(container).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('renders Edit Settings text', () => {
|
|
12
|
+
const { getByText } = render(<MediaToolbar onEdit={jest.fn()} onRemove={jest.fn()} />);
|
|
13
|
+
expect(getByText('Edit Settings')).toBeInTheDocument();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('renders Remove text', () => {
|
|
17
|
+
const { getByText } = render(<MediaToolbar onEdit={jest.fn()} onRemove={jest.fn()} />);
|
|
18
|
+
expect(getByText('Remove')).toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('calls onEdit when Edit Settings is clicked', () => {
|
|
22
|
+
const onEdit = jest.fn();
|
|
23
|
+
const { getByText } = render(<MediaToolbar onEdit={onEdit} onRemove={jest.fn()} />);
|
|
24
|
+
fireEvent.click(getByText('Edit Settings'));
|
|
25
|
+
expect(onEdit).toHaveBeenCalled();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('calls onRemove when Remove is clicked', () => {
|
|
29
|
+
const onRemove = jest.fn();
|
|
30
|
+
const { getByText } = render(<MediaToolbar onEdit={jest.fn()} onRemove={onRemove} />);
|
|
31
|
+
fireEvent.click(getByText('Remove'));
|
|
32
|
+
expect(onRemove).toHaveBeenCalled();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('hides Edit Settings when hideEdit is true', () => {
|
|
36
|
+
const { queryByText } = render(<MediaToolbar hideEdit={true} onEdit={jest.fn()} onRemove={jest.fn()} />);
|
|
37
|
+
expect(queryByText('Edit Settings')).not.toBeInTheDocument();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('shows Edit Settings when hideEdit is false', () => {
|
|
41
|
+
const { getByText } = render(<MediaToolbar hideEdit={false} onEdit={jest.fn()} onRemove={jest.fn()} />);
|
|
42
|
+
expect(getByText('Edit Settings')).toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('applies cursor pointer style', () => {
|
|
46
|
+
const { getByText } = render(<MediaToolbar onEdit={jest.fn()} onRemove={jest.fn()} />);
|
|
47
|
+
const editButton = getByText('Edit Settings');
|
|
48
|
+
expect(editButton).toHaveStyle({ cursor: 'pointer' });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('has border on Edit Settings container', () => {
|
|
52
|
+
const { getByText } = render(<MediaToolbar onEdit={jest.fn()} onRemove={jest.fn()} />);
|
|
53
|
+
const editButton = getByText('Edit Settings');
|
|
54
|
+
expect(editButton).toHaveStyle({ borderWidth: '0 2px 0 0' });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('applies white background', () => {
|
|
58
|
+
const { container } = render(<MediaToolbar onEdit={jest.fn()} onRemove={jest.fn()} />);
|
|
59
|
+
const root = container.firstChild;
|
|
60
|
+
expect(root).toHaveStyle({ background: '#fff' });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('applies box shadow', () => {
|
|
64
|
+
const { container } = render(<MediaToolbar onEdit={jest.fn()} onRemove={jest.fn()} />);
|
|
65
|
+
const root = container.firstChild;
|
|
66
|
+
expect(root).toHaveStyle({ boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)' });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('displays inline-flex', () => {
|
|
70
|
+
const { container } = render(<MediaToolbar onEdit={jest.fn()} onRemove={jest.fn()} />);
|
|
71
|
+
const root = container.firstChild;
|
|
72
|
+
expect(root).toHaveStyle({ display: 'inline-flex' });
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import MediaWrapper from '../media/MediaWrapper';
|
|
4
|
+
|
|
5
|
+
describe('MediaWrapper', () => {
|
|
6
|
+
it('renders without crashing', () => {
|
|
7
|
+
const { container } = render(<MediaWrapper>Content</MediaWrapper>);
|
|
8
|
+
expect(container).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('renders children', () => {
|
|
12
|
+
const { getByText } = render(
|
|
13
|
+
<MediaWrapper>
|
|
14
|
+
<div>Test Content</div>
|
|
15
|
+
</MediaWrapper>,
|
|
16
|
+
);
|
|
17
|
+
expect(getByText('Test Content')).toBeInTheDocument();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('applies default width of 300', () => {
|
|
21
|
+
const { container } = render(<MediaWrapper>Content</MediaWrapper>);
|
|
22
|
+
const wrapper = container.firstChild;
|
|
23
|
+
expect(wrapper).toHaveStyle({ width: '300px' });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('applies custom width from props', () => {
|
|
27
|
+
const { container } = render(<MediaWrapper width={500}>Content</MediaWrapper>);
|
|
28
|
+
const wrapper = container.firstChild;
|
|
29
|
+
expect(wrapper).toHaveStyle({ width: '500px' });
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('applies string width', () => {
|
|
33
|
+
const { container } = render(<MediaWrapper width="50%">Content</MediaWrapper>);
|
|
34
|
+
const wrapper = container.firstChild;
|
|
35
|
+
expect(wrapper).toHaveStyle({ width: '50%' });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('applies editor styles when editor prop is true', () => {
|
|
39
|
+
const { container } = render(<MediaWrapper editor={true}>Content</MediaWrapper>);
|
|
40
|
+
const wrapper = container.firstChild;
|
|
41
|
+
expect(wrapper).toHaveStyle({ display: 'inline-block', overflow: 'hidden' });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('does not apply editor styles when editor prop is false', () => {
|
|
45
|
+
const { container } = render(<MediaWrapper editor={false}>Content</MediaWrapper>);
|
|
46
|
+
const wrapper = container.firstChild;
|
|
47
|
+
expect(wrapper).not.toHaveStyle({ display: 'inline-block' });
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('has relative positioning', () => {
|
|
51
|
+
const { container } = render(<MediaWrapper>Content</MediaWrapper>);
|
|
52
|
+
const wrapper = container.firstChild;
|
|
53
|
+
expect(wrapper).toHaveStyle({ position: 'relative' });
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('renders multiple children', () => {
|
|
57
|
+
const { getByText } = render(
|
|
58
|
+
<MediaWrapper>
|
|
59
|
+
<div>First</div>
|
|
60
|
+
<div>Second</div>
|
|
61
|
+
</MediaWrapper>,
|
|
62
|
+
);
|
|
63
|
+
expect(getByText('First')).toBeInTheDocument();
|
|
64
|
+
expect(getByText('Second')).toBeInTheDocument();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('passes additional props through', () => {
|
|
68
|
+
const { container } = render(
|
|
69
|
+
<MediaWrapper data-testid="custom" className="custom-class">
|
|
70
|
+
Content
|
|
71
|
+
</MediaWrapper>,
|
|
72
|
+
);
|
|
73
|
+
const wrapper = container.firstChild;
|
|
74
|
+
expect(wrapper).toHaveAttribute('data-testid', 'custom');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('renders without children', () => {
|
|
78
|
+
const { container } = render(<MediaWrapper />);
|
|
79
|
+
expect(container.firstChild).toBeInTheDocument();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
|
3
|
+
import StyledMenuBar from '../MenuBar';
|
|
4
|
+
|
|
5
|
+
jest.mock('@tiptap/react', () => ({
|
|
6
|
+
EditorContent: ({ editor }) => <div data-testid="editor-content" />,
|
|
7
|
+
useEditorState: ({ selector }) => {
|
|
8
|
+
const mockEditor = {
|
|
9
|
+
isActive: jest.fn(() => false),
|
|
10
|
+
can: jest.fn(() => ({
|
|
11
|
+
chain: jest.fn(() => ({
|
|
12
|
+
toggleBold: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
13
|
+
insertTable: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
14
|
+
toggleItalic: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
15
|
+
toggleStrike: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
16
|
+
toggleCode: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
17
|
+
unsetAllMarks: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
18
|
+
undo: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
19
|
+
redo: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
20
|
+
})),
|
|
21
|
+
})),
|
|
22
|
+
getAttributes: jest.fn(() => ({ border: '1' })),
|
|
23
|
+
isFocused: true,
|
|
24
|
+
state: {
|
|
25
|
+
selection: {},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return selector({ editor: mockEditor });
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
jest.mock('prosemirror-state', () => ({
|
|
34
|
+
NodeSelection: jest.fn(),
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
jest.mock('../CharacterPicker', () => ({
|
|
38
|
+
CharacterIcon: ({ letter }) => <div data-testid="character-icon">{letter}</div>,
|
|
39
|
+
CharacterPicker: ({ onClose }) => (
|
|
40
|
+
<div data-testid="character-picker">
|
|
41
|
+
<button onClick={onClose} data-testid="close-picker">
|
|
42
|
+
Close
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
),
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
jest.mock('../common/done-button', () => ({
|
|
49
|
+
DoneButton: ({ onClick }) => (
|
|
50
|
+
<button onClick={onClick} data-testid="done-button">
|
|
51
|
+
Done
|
|
52
|
+
</button>
|
|
53
|
+
),
|
|
54
|
+
}));
|
|
55
|
+
|
|
56
|
+
describe('StyledMenuBar', () => {
|
|
57
|
+
const mockEditor = {
|
|
58
|
+
chain: jest.fn(() => ({
|
|
59
|
+
focus: jest.fn(() => ({
|
|
60
|
+
insertTable: jest.fn(() => ({ run: jest.fn() })),
|
|
61
|
+
toggleBold: jest.fn(() => ({ run: jest.fn() })),
|
|
62
|
+
toggleItalic: jest.fn(() => ({ run: jest.fn() })),
|
|
63
|
+
toggleStrike: jest.fn(() => ({ run: jest.fn() })),
|
|
64
|
+
toggleCode: jest.fn(() => ({ run: jest.fn() })),
|
|
65
|
+
toggleUnderline: jest.fn(() => ({ run: jest.fn() })),
|
|
66
|
+
toggleSubscript: jest.fn(() => ({ run: jest.fn() })),
|
|
67
|
+
toggleSuperscript: jest.fn(() => ({ run: jest.fn() })),
|
|
68
|
+
setImageUploadNode: jest.fn(() => ({ run: jest.fn() })),
|
|
69
|
+
insertMedia: jest.fn(() => ({ run: jest.fn() })),
|
|
70
|
+
toggleHeading: jest.fn(() => ({ run: jest.fn() })),
|
|
71
|
+
insertMath: jest.fn(() => ({ run: jest.fn() })),
|
|
72
|
+
toggleBulletList: jest.fn(() => ({ run: jest.fn() })),
|
|
73
|
+
toggleOrderedList: jest.fn(() => ({ run: jest.fn() })),
|
|
74
|
+
undo: jest.fn(() => ({ run: jest.fn() })),
|
|
75
|
+
redo: jest.fn(() => ({ run: jest.fn() })),
|
|
76
|
+
addRowAfter: jest.fn(() => ({ run: jest.fn() })),
|
|
77
|
+
deleteRow: jest.fn(() => ({ run: jest.fn() })),
|
|
78
|
+
addColumnAfter: jest.fn(() => ({ run: jest.fn() })),
|
|
79
|
+
deleteColumn: jest.fn(() => ({ run: jest.fn() })),
|
|
80
|
+
deleteTable: jest.fn(() => ({ run: jest.fn() })),
|
|
81
|
+
insertResponseArea: jest.fn(() => ({ run: jest.fn() })),
|
|
82
|
+
})),
|
|
83
|
+
})),
|
|
84
|
+
can: jest.fn(() => ({
|
|
85
|
+
chain: jest.fn(() => ({
|
|
86
|
+
toggleBold: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
87
|
+
insertTable: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
88
|
+
undo: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
89
|
+
redo: jest.fn(() => ({ run: jest.fn(() => true) })),
|
|
90
|
+
})),
|
|
91
|
+
})),
|
|
92
|
+
isActive: jest.fn((name) => {
|
|
93
|
+
if (name === 'bold') return true;
|
|
94
|
+
if (name === 'italic') return false;
|
|
95
|
+
return false;
|
|
96
|
+
}),
|
|
97
|
+
getAttributes: jest.fn(() => ({ border: '1' })),
|
|
98
|
+
getHTML: jest.fn(() => '<p>Test</p>'),
|
|
99
|
+
commands: {
|
|
100
|
+
blur: jest.fn(),
|
|
101
|
+
openCSSClassDialog: jest.fn(),
|
|
102
|
+
updateAttributes: jest.fn(),
|
|
103
|
+
},
|
|
104
|
+
isFocused: true,
|
|
105
|
+
state: {
|
|
106
|
+
selection: {},
|
|
107
|
+
},
|
|
108
|
+
_toolbarOpened: false,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const defaultProps = {
|
|
112
|
+
editor: mockEditor,
|
|
113
|
+
activePlugins: ['bold', 'italic', 'underline', 'table'],
|
|
114
|
+
toolbarOpts: {},
|
|
115
|
+
responseAreaProps: { type: 'explicit-constructed-response' },
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
beforeEach(() => {
|
|
119
|
+
jest.clearAllMocks();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('renders without crashing', () => {
|
|
123
|
+
const { container } = render(<StyledMenuBar {...defaultProps} />);
|
|
124
|
+
expect(container).toBeInTheDocument();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('renders toolbar with buttons', () => {
|
|
128
|
+
const { container } = render(<StyledMenuBar {...defaultProps} />);
|
|
129
|
+
const buttons = container.querySelectorAll('button');
|
|
130
|
+
expect(buttons.length).toBeGreaterThan(0);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('shows bold button when bold plugin is active', () => {
|
|
134
|
+
const { container } = render(<StyledMenuBar {...defaultProps} />);
|
|
135
|
+
expect(container).toBeInTheDocument();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('hides buttons when isTable is true', () => {
|
|
139
|
+
const { container } = render(<StyledMenuBar {...defaultProps} activePlugins={['table']} />);
|
|
140
|
+
expect(container).toBeInTheDocument();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('shows table buttons when in table context', () => {
|
|
144
|
+
const { container } = render(<StyledMenuBar {...defaultProps} activePlugins={['table']} />);
|
|
145
|
+
expect(container).toBeInTheDocument();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('handles button clicks', () => {
|
|
149
|
+
const { container } = render(<StyledMenuBar {...defaultProps} />);
|
|
150
|
+
const button = container.querySelector('button');
|
|
151
|
+
if (button) {
|
|
152
|
+
fireEvent.click(button);
|
|
153
|
+
}
|
|
154
|
+
expect(container).toBeInTheDocument();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('shows done button when toolbarOpts.showDone is true', () => {
|
|
158
|
+
const { getByTestId } = render(
|
|
159
|
+
<StyledMenuBar {...defaultProps} toolbarOpts={{ showDone: true }} onChange={jest.fn()} />,
|
|
160
|
+
);
|
|
161
|
+
expect(getByTestId('done-button')).toBeInTheDocument();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('does not show done button when toolbarOpts.showDone is false', () => {
|
|
165
|
+
const { queryByTestId } = render(<StyledMenuBar {...defaultProps} toolbarOpts={{ showDone: false }} />);
|
|
166
|
+
expect(queryByTestId('done-button')).not.toBeInTheDocument();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('handles done button click', () => {
|
|
170
|
+
const onChange = jest.fn();
|
|
171
|
+
const { getByTestId } = render(
|
|
172
|
+
<StyledMenuBar {...defaultProps} toolbarOpts={{ showDone: true }} onChange={onChange} />,
|
|
173
|
+
);
|
|
174
|
+
fireEvent.click(getByTestId('done-button'));
|
|
175
|
+
expect(onChange).toHaveBeenCalledWith('<p>Test</p>');
|
|
176
|
+
expect(mockEditor.commands.blur).toHaveBeenCalled();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('applies custom minWidth from toolbarOpts', () => {
|
|
180
|
+
const { container } = render(<StyledMenuBar {...defaultProps} toolbarOpts={{ minWidth: 500 }} />);
|
|
181
|
+
const toolbar = container.querySelector('.toolbar');
|
|
182
|
+
expect(toolbar).toHaveStyle({ minWidth: '500px' });
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('applies hidden class when toolbarOpts.isHidden is true', () => {
|
|
186
|
+
const { container } = render(<StyledMenuBar {...defaultProps} toolbarOpts={{ isHidden: true }} />);
|
|
187
|
+
const toolbar = container.querySelector('.toolbar');
|
|
188
|
+
expect(toolbar).toHaveClass('hidden');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('shows character picker when language character button is clicked', () => {
|
|
192
|
+
const { container, queryByTestId } = render(
|
|
193
|
+
<StyledMenuBar {...defaultProps} activePlugins={['languageCharacters']} />,
|
|
194
|
+
);
|
|
195
|
+
expect(queryByTestId('character-picker')).not.toBeInTheDocument();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('applies focused class when editor is focused', () => {
|
|
199
|
+
const { container } = render(<StyledMenuBar {...defaultProps} toolbarOpts={{ alwaysVisible: false }} />);
|
|
200
|
+
const toolbar = container.querySelector('.toolbar');
|
|
201
|
+
expect(toolbar).toHaveClass('focused');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('shows response area button when responseArea plugin is active', () => {
|
|
205
|
+
const { container } = render(<StyledMenuBar {...defaultProps} activePlugins={['responseArea']} />);
|
|
206
|
+
expect(container).toBeInTheDocument();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('prevents default on mouse down', () => {
|
|
210
|
+
const { container } = render(<StyledMenuBar {...defaultProps} />);
|
|
211
|
+
const toolbar = container.querySelector('.toolbar');
|
|
212
|
+
const event = new MouseEvent('mousedown', { bubbles: true, cancelable: true });
|
|
213
|
+
const preventDefaultSpy = jest.spyOn(event, 'preventDefault');
|
|
214
|
+
toolbar?.dispatchEvent(event);
|
|
215
|
+
expect(preventDefaultSpy).toHaveBeenCalled();
|
|
216
|
+
});
|
|
217
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import { Chevron, GripIcon, ToolbarIcon } from '../icons/RespArea';
|
|
4
|
+
|
|
5
|
+
describe('Chevron', () => {
|
|
6
|
+
it('renders without crashing', () => {
|
|
7
|
+
const { container } = render(<Chevron />);
|
|
8
|
+
expect(container).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('rotates 0 degrees for right direction (default)', () => {
|
|
12
|
+
const { container } = render(<Chevron direction="right" />);
|
|
13
|
+
const svg = container.querySelector('svg');
|
|
14
|
+
expect(svg).toHaveStyle({ transform: 'rotate(0deg)' });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('rotates 90 degrees for down direction', () => {
|
|
18
|
+
const { container } = render(<Chevron direction="down" />);
|
|
19
|
+
const svg = container.querySelector('svg');
|
|
20
|
+
expect(svg).toHaveStyle({ transform: 'rotate(90deg)' });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('rotates -90 degrees for up direction', () => {
|
|
24
|
+
const { container } = render(<Chevron direction="up" />);
|
|
25
|
+
const svg = container.querySelector('svg');
|
|
26
|
+
expect(svg).toHaveStyle({ transform: 'rotate(-90deg)' });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('rotates 180 degrees for left direction', () => {
|
|
30
|
+
const { container } = render(<Chevron direction="left" />);
|
|
31
|
+
const svg = container.querySelector('svg');
|
|
32
|
+
expect(svg).toHaveStyle({ transform: 'rotate(180deg)' });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('applies custom style prop', () => {
|
|
36
|
+
const customStyle = { color: 'red', fontSize: '20px' };
|
|
37
|
+
const { container } = render(<Chevron style={customStyle} />);
|
|
38
|
+
const svg = container.querySelector('svg');
|
|
39
|
+
expect(svg).toHaveStyle({ color: 'red', fontSize: '20px' });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('defaults to 0 rotation when no direction specified', () => {
|
|
43
|
+
const { container } = render(<Chevron />);
|
|
44
|
+
const svg = container.querySelector('svg');
|
|
45
|
+
expect(svg).toHaveStyle({ transform: 'rotate(0deg)' });
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('GripIcon', () => {
|
|
50
|
+
it('renders without crashing', () => {
|
|
51
|
+
const { container } = render(<GripIcon />);
|
|
52
|
+
expect(container).toBeInTheDocument();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('renders two MoreVert icons', () => {
|
|
56
|
+
const { container } = render(<GripIcon />);
|
|
57
|
+
const moreVertIcons = container.querySelectorAll('svg');
|
|
58
|
+
expect(moreVertIcons.length).toBe(2);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('applies custom style prop', () => {
|
|
62
|
+
const customStyle = { color: 'blue' };
|
|
63
|
+
const { container } = render(<GripIcon style={customStyle} />);
|
|
64
|
+
const span = container.querySelector('span');
|
|
65
|
+
expect(span).toHaveStyle({ color: 'blue' });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('applies negative margin to first icon', () => {
|
|
69
|
+
const { container } = render(<GripIcon />);
|
|
70
|
+
const firstIcon = container.querySelector('svg');
|
|
71
|
+
expect(firstIcon).toHaveStyle({ margin: '0 -16px' });
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('ToolbarIcon', () => {
|
|
76
|
+
it('renders without crashing', () => {
|
|
77
|
+
const { container } = render(<ToolbarIcon />);
|
|
78
|
+
expect(container).toBeInTheDocument();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('renders "+ Response Area" text', () => {
|
|
82
|
+
const { getByText } = render(<ToolbarIcon />);
|
|
83
|
+
expect(getByText('+ Response Area')).toBeInTheDocument();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('applies correct font family', () => {
|
|
87
|
+
const { getByText } = render(<ToolbarIcon />);
|
|
88
|
+
const element = getByText('+ Response Area');
|
|
89
|
+
// Font family is applied via styled component, just verify text renders
|
|
90
|
+
expect(element).toBeInTheDocument();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('applies bold font weight', () => {
|
|
94
|
+
const { getByText } = render(<ToolbarIcon />);
|
|
95
|
+
const element = getByText('+ Response Area');
|
|
96
|
+
expect(element).toHaveStyle({ fontWeight: 'bold' });
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('has correct dimensions', () => {
|
|
100
|
+
const { getByText } = render(<ToolbarIcon />);
|
|
101
|
+
const element = getByText('+ Response Area');
|
|
102
|
+
expect(element).toHaveStyle({ width: '110px', height: '28px' });
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('has relative positioning', () => {
|
|
106
|
+
const { getByText } = render(<ToolbarIcon />);
|
|
107
|
+
const element = getByText('+ Response Area');
|
|
108
|
+
expect(element).toHaveStyle({ position: 'relative' });
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('has nowrap white space', () => {
|
|
112
|
+
const { getByText } = render(<ToolbarIcon />);
|
|
113
|
+
const element = getByText('+ Response Area');
|
|
114
|
+
expect(element).toHaveStyle({ whiteSpace: 'nowrap' });
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('has top offset', () => {
|
|
118
|
+
const { getByText } = render(<ToolbarIcon />);
|
|
119
|
+
const element = getByText('+ Response Area');
|
|
120
|
+
expect(element).toHaveStyle({ top: '7px' });
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import { AddRow, RemoveRow, AddColumn, RemoveColumn, RemoveTable } from '../icons/TableIcons';
|
|
4
|
+
|
|
5
|
+
describe('AddRow', () => {
|
|
6
|
+
it('renders without crashing', () => {
|
|
7
|
+
const { container } = render(<AddRow />);
|
|
8
|
+
expect(container).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('renders SVG', () => {
|
|
12
|
+
const { container } = render(<AddRow />);
|
|
13
|
+
const svg = container.querySelector('svg');
|
|
14
|
+
expect(svg).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('has correct viewBox', () => {
|
|
18
|
+
const { container } = render(<AddRow />);
|
|
19
|
+
const svg = container.querySelector('svg');
|
|
20
|
+
expect(svg).toHaveAttribute('viewBox', '0 0 24 24');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('has correct dimensions', () => {
|
|
24
|
+
const { container } = render(<AddRow />);
|
|
25
|
+
const svg = container.querySelector('svg');
|
|
26
|
+
expect(svg).toHaveAttribute('width', '24');
|
|
27
|
+
expect(svg).toHaveAttribute('height', '24');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('contains path element', () => {
|
|
31
|
+
const { container } = render(<AddRow />);
|
|
32
|
+
const path = container.querySelector('path');
|
|
33
|
+
expect(path).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('RemoveRow', () => {
|
|
38
|
+
it('renders without crashing', () => {
|
|
39
|
+
const { container } = render(<RemoveRow />);
|
|
40
|
+
expect(container).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('renders SVG', () => {
|
|
44
|
+
const { container } = render(<RemoveRow />);
|
|
45
|
+
const svg = container.querySelector('svg');
|
|
46
|
+
expect(svg).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('has correct viewBox', () => {
|
|
50
|
+
const { container } = render(<RemoveRow />);
|
|
51
|
+
const svg = container.querySelector('svg');
|
|
52
|
+
expect(svg).toHaveAttribute('viewBox', '0 0 24 24');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('contains path element', () => {
|
|
56
|
+
const { container } = render(<RemoveRow />);
|
|
57
|
+
const path = container.querySelector('path');
|
|
58
|
+
expect(path).toBeInTheDocument();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('AddColumn', () => {
|
|
63
|
+
it('renders without crashing', () => {
|
|
64
|
+
const { container } = render(<AddColumn />);
|
|
65
|
+
expect(container).toBeInTheDocument();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('renders SVG', () => {
|
|
69
|
+
const { container } = render(<AddColumn />);
|
|
70
|
+
const svg = container.querySelector('svg');
|
|
71
|
+
expect(svg).toBeInTheDocument();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('has correct viewBox', () => {
|
|
75
|
+
const { container } = render(<AddColumn />);
|
|
76
|
+
const svg = container.querySelector('svg');
|
|
77
|
+
expect(svg).toHaveAttribute('viewBox', '0 0 24 24');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('has correct dimensions', () => {
|
|
81
|
+
const { container } = render(<AddColumn />);
|
|
82
|
+
const svg = container.querySelector('svg');
|
|
83
|
+
expect(svg).toHaveAttribute('width', '24');
|
|
84
|
+
expect(svg).toHaveAttribute('height', '24');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('contains path element', () => {
|
|
88
|
+
const { container } = render(<AddColumn />);
|
|
89
|
+
const path = container.querySelector('path');
|
|
90
|
+
expect(path).toBeInTheDocument();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('RemoveColumn', () => {
|
|
95
|
+
it('renders without crashing', () => {
|
|
96
|
+
const { container } = render(<RemoveColumn />);
|
|
97
|
+
expect(container).toBeInTheDocument();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('renders SVG', () => {
|
|
101
|
+
const { container } = render(<RemoveColumn />);
|
|
102
|
+
const svg = container.querySelector('svg');
|
|
103
|
+
expect(svg).toBeInTheDocument();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('has correct viewBox', () => {
|
|
107
|
+
const { container } = render(<RemoveColumn />);
|
|
108
|
+
const svg = container.querySelector('svg');
|
|
109
|
+
expect(svg).toHaveAttribute('viewBox', '0 0 24 24');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('contains path element', () => {
|
|
113
|
+
const { container } = render(<RemoveColumn />);
|
|
114
|
+
const path = container.querySelector('path');
|
|
115
|
+
expect(path).toBeInTheDocument();
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('RemoveTable', () => {
|
|
120
|
+
it('renders without crashing', () => {
|
|
121
|
+
const { container } = render(<RemoveTable />);
|
|
122
|
+
expect(container).toBeInTheDocument();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('renders SVG', () => {
|
|
126
|
+
const { container } = render(<RemoveTable />);
|
|
127
|
+
const svg = container.querySelector('svg');
|
|
128
|
+
expect(svg).toBeInTheDocument();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('has correct viewBox', () => {
|
|
132
|
+
const { container } = render(<RemoveTable />);
|
|
133
|
+
const svg = container.querySelector('svg');
|
|
134
|
+
expect(svg).toHaveAttribute('viewBox', '0 0 24 24');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('has correct dimensions', () => {
|
|
138
|
+
const { container } = render(<RemoveTable />);
|
|
139
|
+
const svg = container.querySelector('svg');
|
|
140
|
+
expect(svg).toHaveAttribute('width', '24');
|
|
141
|
+
expect(svg).toHaveAttribute('height', '24');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('contains path element', () => {
|
|
145
|
+
const { container } = render(<RemoveTable />);
|
|
146
|
+
const path = container.querySelector('path');
|
|
147
|
+
expect(path).toBeInTheDocument();
|
|
148
|
+
});
|
|
149
|
+
});
|