Unit test MessageActionBar (#8732)
* test most basic paths in messageactionbar Signed-off-by: Kerry Archibald <kerrya@element.io> * tidy Signed-off-by: Kerry Archibald <kerrya@element.io> * add rtl * add code style note about using rtl Signed-off-by: Kerry Archibald <kerrya@element.io> * downgrade to rtl 12 * use rtl for MessageActionBar test Signed-off-by: Kerry Archibald <kerrya@element.io> * try mocking settingsstore for ci only failure Signed-off-by: Kerry Archibald <kerrya@element.io> * mock setValue too Signed-off-by: Kerry Archibald <kerrya@element.io> * uupdate lockfile Signed-off-by: Kerry Archibald <kerrya@element.io>
This commit is contained in:
parent
7c57680b93
commit
158e42f764
8 changed files with 436 additions and 2 deletions
|
@ -208,3 +208,7 @@ React
|
||||||
information in component state that could be derived from the model?
|
information in component state that could be derived from the model?
|
||||||
|
|
||||||
- Avoid things marked as Legacy or Deprecated in React 16 (e.g string refs and legacy contexts)
|
- Avoid things marked as Legacy or Deprecated in React 16 (e.g string refs and legacy contexts)
|
||||||
|
|
||||||
|
Unit tests
|
||||||
|
-----
|
||||||
|
- New tests should use [react testing library](https://testing-library.com/docs/react-testing-library/intro/)
|
|
@ -58,6 +58,7 @@
|
||||||
"@babel/runtime": "^7.12.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
"@sentry/browser": "^6.11.0",
|
"@sentry/browser": "^6.11.0",
|
||||||
"@sentry/tracing": "^6.11.0",
|
"@sentry/tracing": "^6.11.0",
|
||||||
|
"@testing-library/react": "^12.1.5",
|
||||||
"@types/geojson": "^7946.0.8",
|
"@types/geojson": "^7946.0.8",
|
||||||
"await-lock": "^2.1.0",
|
"await-lock": "^2.1.0",
|
||||||
"blurhash": "^1.1.3",
|
"blurhash": "^1.1.3",
|
||||||
|
|
|
@ -670,6 +670,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
{...this.props}
|
{...this.props}
|
||||||
className="mx_MessageContextMenu"
|
className="mx_MessageContextMenu"
|
||||||
compact={true}
|
compact={true}
|
||||||
|
data-testid="mx_MessageContextMenu"
|
||||||
>
|
>
|
||||||
{ nativeItemsList }
|
{ nativeItemsList }
|
||||||
{ quickItemsList }
|
{ quickItemsList }
|
||||||
|
|
|
@ -124,6 +124,7 @@ class ReactionPicker extends React.Component<IProps, IState> {
|
||||||
onChoose={this.onChoose}
|
onChoose={this.onChoose}
|
||||||
selectedEmojis={this.state.selectedEmojis}
|
selectedEmojis={this.state.selectedEmojis}
|
||||||
showQuickReactions={true}
|
showQuickReactions={true}
|
||||||
|
data-testid='mx_ReactionPicker'
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
363
test/components/views/messages/MessageActionBar-test.tsx
Normal file
363
test/components/views/messages/MessageActionBar-test.tsx
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { render, fireEvent } from '@testing-library/react';
|
||||||
|
import { act } from 'react-test-renderer';
|
||||||
|
import {
|
||||||
|
EventType,
|
||||||
|
EventStatus,
|
||||||
|
MatrixEvent,
|
||||||
|
MatrixEventEvent,
|
||||||
|
MsgType,
|
||||||
|
Room,
|
||||||
|
} from 'matrix-js-sdk/src/matrix';
|
||||||
|
|
||||||
|
import MessageActionBar from '../../../../src/components/views/messages/MessageActionBar';
|
||||||
|
import {
|
||||||
|
getMockClientWithEventEmitter,
|
||||||
|
mockClientMethodsUser,
|
||||||
|
mockClientMethodsEvents,
|
||||||
|
} from '../../../test-utils';
|
||||||
|
import { RoomPermalinkCreator } from '../../../../src/utils/permalinks/Permalinks';
|
||||||
|
import RoomContext, { TimelineRenderingType } from '../../../../src/contexts/RoomContext';
|
||||||
|
import { IRoomState } from '../../../../src/components/structures/RoomView';
|
||||||
|
import dispatcher from '../../../../src/dispatcher/dispatcher';
|
||||||
|
import SettingsStore from '../../../../src/settings/SettingsStore';
|
||||||
|
|
||||||
|
jest.mock('../../../../src/dispatcher/dispatcher');
|
||||||
|
|
||||||
|
describe('<MessageActionBar />', () => {
|
||||||
|
const userId = '@alice:server.org';
|
||||||
|
const roomId = '!room:server.org';
|
||||||
|
const alicesMessageEvent = new MatrixEvent({
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
sender: userId,
|
||||||
|
room_id: roomId,
|
||||||
|
content: {
|
||||||
|
msgtype: MsgType.Text,
|
||||||
|
body: 'Hello',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const bobsMessageEvent = new MatrixEvent({
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
sender: '@bob:server.org',
|
||||||
|
room_id: roomId,
|
||||||
|
content: {
|
||||||
|
msgtype: MsgType.Text,
|
||||||
|
body: 'I am bob',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const redactedEvent = new MatrixEvent({
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
sender: userId,
|
||||||
|
});
|
||||||
|
redactedEvent.makeRedacted(redactedEvent);
|
||||||
|
|
||||||
|
const client = getMockClientWithEventEmitter({
|
||||||
|
...mockClientMethodsUser(userId),
|
||||||
|
...mockClientMethodsEvents(),
|
||||||
|
getRoom: jest.fn(),
|
||||||
|
});
|
||||||
|
const room = new Room(roomId, client, userId);
|
||||||
|
jest.spyOn(room, 'getPendingEvents').mockReturnValue([]);
|
||||||
|
|
||||||
|
client.getRoom.mockReturnValue(room);
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
getTile: jest.fn(),
|
||||||
|
getReplyChain: jest.fn(),
|
||||||
|
toggleThreadExpanded: jest.fn(),
|
||||||
|
mxEvent: alicesMessageEvent,
|
||||||
|
permalinkCreator: new RoomPermalinkCreator(room),
|
||||||
|
};
|
||||||
|
const defaultRoomContext = {
|
||||||
|
...RoomContext,
|
||||||
|
timelineRenderingType: TimelineRenderingType.Room,
|
||||||
|
canSendMessages: true,
|
||||||
|
canReact: true,
|
||||||
|
} as unknown as IRoomState;
|
||||||
|
const getComponent = (props = {}, roomContext: Partial<IRoomState> = {}) =>
|
||||||
|
render(
|
||||||
|
<RoomContext.Provider value={{ ...defaultRoomContext, ...roomContext }}>
|
||||||
|
<MessageActionBar {...defaultProps} {...props} />
|
||||||
|
</RoomContext.Provider>);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
alicesMessageEvent.setStatus(EventStatus.SENT);
|
||||||
|
jest.spyOn(SettingsStore, 'getValue').mockReturnValue(false);
|
||||||
|
jest.spyOn(SettingsStore, 'setValue').mockResolvedValue(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.spyOn(SettingsStore, 'getValue').mockRestore();
|
||||||
|
jest.spyOn(SettingsStore, 'setValue').mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('kills event listeners on unmount', () => {
|
||||||
|
const offSpy = jest.spyOn(alicesMessageEvent, 'off').mockClear();
|
||||||
|
const wrapper = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(offSpy.mock.calls[0][0]).toEqual(MatrixEventEvent.Status);
|
||||||
|
expect(offSpy.mock.calls[1][0]).toEqual(MatrixEventEvent.Decrypted);
|
||||||
|
expect(offSpy.mock.calls[2][0]).toEqual(MatrixEventEvent.BeforeRedaction);
|
||||||
|
|
||||||
|
expect(client.decryptEventIfNeeded).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('decryption', () => {
|
||||||
|
it('decrypts event if needed', () => {
|
||||||
|
getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
expect(client.decryptEventIfNeeded).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates component on decrypted event', () => {
|
||||||
|
const decryptingEvent = new MatrixEvent({
|
||||||
|
type: EventType.RoomMessageEncrypted,
|
||||||
|
sender: userId,
|
||||||
|
room_id: roomId,
|
||||||
|
content: {},
|
||||||
|
});
|
||||||
|
jest.spyOn(decryptingEvent, 'isBeingDecrypted').mockReturnValue(true);
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: decryptingEvent });
|
||||||
|
|
||||||
|
// still encrypted event is not actionable => no reply button
|
||||||
|
expect(queryByLabelText('Reply')).toBeFalsy();
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
// ''decrypt'' the event
|
||||||
|
decryptingEvent.event.type = alicesMessageEvent.getType();
|
||||||
|
decryptingEvent.event.content = alicesMessageEvent.getContent();
|
||||||
|
decryptingEvent.emit(MatrixEventEvent.Decrypted, decryptingEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
// new available actions after decryption
|
||||||
|
expect(queryByLabelText('Reply')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('status', () => {
|
||||||
|
it('updates component when event status changes', () => {
|
||||||
|
alicesMessageEvent.setStatus(EventStatus.QUEUED);
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
|
||||||
|
// pending event status, cancel action available
|
||||||
|
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
alicesMessageEvent.setStatus(EventStatus.SENT);
|
||||||
|
});
|
||||||
|
|
||||||
|
// event is sent, no longer cancelable
|
||||||
|
expect(queryByLabelText('Delete')).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('redaction', () => {
|
||||||
|
// this doesn't do what it's supposed to
|
||||||
|
// because beforeRedaction event is fired... before redaction
|
||||||
|
// event is unchanged at point when this component updates
|
||||||
|
// TODO file bug
|
||||||
|
xit('updates component on before redaction event', () => {
|
||||||
|
const event = new MatrixEvent({
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
sender: userId,
|
||||||
|
room_id: roomId,
|
||||||
|
content: {
|
||||||
|
msgtype: MsgType.Text,
|
||||||
|
body: 'Hello',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: event });
|
||||||
|
|
||||||
|
// no pending redaction => no delete button
|
||||||
|
expect(queryByLabelText('Delete')).toBeFalsy();
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
const redactionEvent = new MatrixEvent({
|
||||||
|
type: EventType.RoomRedaction,
|
||||||
|
sender: userId,
|
||||||
|
room_id: roomId,
|
||||||
|
});
|
||||||
|
redactionEvent.setStatus(EventStatus.QUEUED);
|
||||||
|
event.markLocallyRedacted(redactionEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
// updated with local redaction event, delete now available
|
||||||
|
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('options button', () => {
|
||||||
|
it('renders options menu', () => {
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
expect(queryByLabelText('Options')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('opens message context menu on click', () => {
|
||||||
|
const { findByTestId, queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
act(() => {
|
||||||
|
fireEvent.click(queryByLabelText('Options'));
|
||||||
|
});
|
||||||
|
expect(findByTestId('mx_MessageContextMenu')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('reply button', () => {
|
||||||
|
it('renders reply button on own actionable event', () => {
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
expect(queryByLabelText('Reply')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders reply button on others actionable event', () => {
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: bobsMessageEvent }, { canSendMessages: true });
|
||||||
|
expect(queryByLabelText('Reply')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not render reply button on non-actionable event', () => {
|
||||||
|
// redacted event is not actionable
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: redactedEvent });
|
||||||
|
expect(queryByLabelText('Reply')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not render reply button when user cannot send messaged', () => {
|
||||||
|
// redacted event is not actionable
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: redactedEvent }, { canSendMessages: false });
|
||||||
|
expect(queryByLabelText('Reply')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispatches reply event on click', () => {
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
fireEvent.click(queryByLabelText('Reply'));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(dispatcher.dispatch).toHaveBeenCalledWith({
|
||||||
|
action: 'reply_to_event',
|
||||||
|
event: alicesMessageEvent,
|
||||||
|
context: TimelineRenderingType.Room,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('react button', () => {
|
||||||
|
it('renders react button on own actionable event', () => {
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
expect(queryByLabelText('React')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders react button on others actionable event', () => {
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: bobsMessageEvent });
|
||||||
|
expect(queryByLabelText('React')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not render react button on non-actionable event', () => {
|
||||||
|
// redacted event is not actionable
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: redactedEvent });
|
||||||
|
expect(queryByLabelText('React')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not render react button when user cannot react', () => {
|
||||||
|
// redacted event is not actionable
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: redactedEvent }, { canReact: false });
|
||||||
|
expect(queryByLabelText('React')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('opens reaction picker on click', () => {
|
||||||
|
const { queryByLabelText, findByTestId } = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
act(() => {
|
||||||
|
fireEvent.click(queryByLabelText('React'));
|
||||||
|
});
|
||||||
|
expect(findByTestId('mx_ReactionPicker')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cancel button', () => {
|
||||||
|
it('renders cancel button for an event with a cancelable status', () => {
|
||||||
|
alicesMessageEvent.setStatus(EventStatus.QUEUED);
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders cancel button for an event with a pending edit', () => {
|
||||||
|
const event = new MatrixEvent({
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
sender: userId,
|
||||||
|
room_id: roomId,
|
||||||
|
content: {
|
||||||
|
msgtype: MsgType.Text,
|
||||||
|
body: 'Hello',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
event.setStatus(EventStatus.SENT);
|
||||||
|
const replacingEvent = new MatrixEvent({
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
sender: userId,
|
||||||
|
room_id: roomId,
|
||||||
|
content: {
|
||||||
|
msgtype: MsgType.Text,
|
||||||
|
body: 'replacing event body',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
replacingEvent.setStatus(EventStatus.QUEUED);
|
||||||
|
event.makeReplaced(replacingEvent);
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: event });
|
||||||
|
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders cancel button for an event with a pending redaction', () => {
|
||||||
|
const event = new MatrixEvent({
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
sender: userId,
|
||||||
|
room_id: roomId,
|
||||||
|
content: {
|
||||||
|
msgtype: MsgType.Text,
|
||||||
|
body: 'Hello',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
event.setStatus(EventStatus.SENT);
|
||||||
|
|
||||||
|
const redactionEvent = new MatrixEvent({
|
||||||
|
type: EventType.RoomRedaction,
|
||||||
|
sender: userId,
|
||||||
|
room_id: roomId,
|
||||||
|
});
|
||||||
|
redactionEvent.setStatus(EventStatus.QUEUED);
|
||||||
|
|
||||||
|
event.markLocallyRedacted(redactionEvent);
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: event });
|
||||||
|
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders cancel and retry button for an event with NOT_SENT status', () => {
|
||||||
|
alicesMessageEvent.setStatus(EventStatus.NOT_SENT);
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
expect(queryByLabelText('Retry')).toBeTruthy();
|
||||||
|
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.todo('unsends event on cancel click');
|
||||||
|
it.todo('retrys event on retry click');
|
||||||
|
});
|
||||||
|
});
|
|
@ -67,4 +67,17 @@ export const mockClientMethodsUser = (userId = '@alice:domain') => ({
|
||||||
getUserId: jest.fn().mockReturnValue(userId),
|
getUserId: jest.fn().mockReturnValue(userId),
|
||||||
isGuest: jest.fn().mockReturnValue(false),
|
isGuest: jest.fn().mockReturnValue(false),
|
||||||
mxcUrlToHttp: jest.fn().mockReturnValue('mock-mxcUrlToHttp'),
|
mxcUrlToHttp: jest.fn().mockReturnValue('mock-mxcUrlToHttp'),
|
||||||
|
credentials: { userId },
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns basic mocked client methods related to rendering events
|
||||||
|
* ```
|
||||||
|
* const mockClient = getMockClientWithEventEmitter({
|
||||||
|
...mockClientMethodsUser('@mytestuser:domain'),
|
||||||
|
});
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const mockClientMethodsEvents = () => ({
|
||||||
|
decryptEventIfNeeded: jest.fn(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -38,6 +38,7 @@ export function untilDispatch(waitForAction: DispatcherAction): Promise<ActionPa
|
||||||
const findByAttr = (attr: string) => (component: ReactWrapper, value: string) => component.find(`[${attr}="${value}"]`);
|
const findByAttr = (attr: string) => (component: ReactWrapper, value: string) => component.find(`[${attr}="${value}"]`);
|
||||||
export const findByTestId = findByAttr('data-test-id');
|
export const findByTestId = findByAttr('data-test-id');
|
||||||
export const findById = findByAttr('id');
|
export const findById = findByAttr('id');
|
||||||
|
export const findByAriaLabel = findByAttr('aria-label');
|
||||||
|
|
||||||
const findByTagAndAttr = (attr: string) =>
|
const findByTagAndAttr = (attr: string) =>
|
||||||
(component: ReactWrapper, value: string, tag: string) =>
|
(component: ReactWrapper, value: string, tag: string) =>
|
||||||
|
|
54
yarn.lock
54
yarn.lock
|
@ -50,7 +50,7 @@
|
||||||
"@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3"
|
"@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3"
|
||||||
chokidar "^3.4.0"
|
chokidar "^3.4.0"
|
||||||
|
|
||||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7":
|
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7":
|
||||||
version "7.16.7"
|
version "7.16.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
|
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
|
||||||
integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==
|
integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==
|
||||||
|
@ -1852,11 +1852,39 @@
|
||||||
remark "^13.0.0"
|
remark "^13.0.0"
|
||||||
unist-util-find-all-after "^3.0.2"
|
unist-util-find-all-after "^3.0.2"
|
||||||
|
|
||||||
|
"@testing-library/dom@^8.0.0":
|
||||||
|
version "8.13.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.13.0.tgz#bc00bdd64c7d8b40841e27a70211399ad3af46f5"
|
||||||
|
integrity sha512-9VHgfIatKNXQNaZTtLnalIy0jNZzY35a4S3oi08YAt9Hv1VsfZ/DfA45lM8D/UhtHBGJ4/lGwp0PZkVndRkoOQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/code-frame" "^7.10.4"
|
||||||
|
"@babel/runtime" "^7.12.5"
|
||||||
|
"@types/aria-query" "^4.2.0"
|
||||||
|
aria-query "^5.0.0"
|
||||||
|
chalk "^4.1.0"
|
||||||
|
dom-accessibility-api "^0.5.9"
|
||||||
|
lz-string "^1.4.4"
|
||||||
|
pretty-format "^27.0.2"
|
||||||
|
|
||||||
|
"@testing-library/react@^12.1.5":
|
||||||
|
version "12.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.5.tgz#bb248f72f02a5ac9d949dea07279095fa577963b"
|
||||||
|
integrity sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.5"
|
||||||
|
"@testing-library/dom" "^8.0.0"
|
||||||
|
"@types/react-dom" "<18.0.0"
|
||||||
|
|
||||||
"@tootallnate/once@1":
|
"@tootallnate/once@1":
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||||
|
|
||||||
|
"@types/aria-query@^4.2.0":
|
||||||
|
version "4.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc"
|
||||||
|
integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==
|
||||||
|
|
||||||
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.7":
|
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.7":
|
||||||
version "7.1.19"
|
version "7.1.19"
|
||||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460"
|
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460"
|
||||||
|
@ -2107,6 +2135,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/react-dom@<18.0.0":
|
||||||
|
version "17.0.17"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.17.tgz#2e3743277a793a96a99f1bf87614598289da68a1"
|
||||||
|
integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "^17"
|
||||||
|
|
||||||
"@types/react-redux@^7.1.20":
|
"@types/react-redux@^7.1.20":
|
||||||
version "7.1.24"
|
version "7.1.24"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.24.tgz#6caaff1603aba17b27d20f8ad073e4c077e975c0"
|
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.24.tgz#6caaff1603aba17b27d20f8ad073e4c077e975c0"
|
||||||
|
@ -2484,6 +2519,11 @@ aria-query@^4.2.2:
|
||||||
"@babel/runtime" "^7.10.2"
|
"@babel/runtime" "^7.10.2"
|
||||||
"@babel/runtime-corejs3" "^7.10.2"
|
"@babel/runtime-corejs3" "^7.10.2"
|
||||||
|
|
||||||
|
aria-query@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.0.0.tgz#210c21aaf469613ee8c9a62c7f86525e058db52c"
|
||||||
|
integrity sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==
|
||||||
|
|
||||||
arr-diff@^4.0.0:
|
arr-diff@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
|
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
|
||||||
|
@ -3744,6 +3784,11 @@ doctrine@^3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
|
|
||||||
|
dom-accessibility-api@^0.5.9:
|
||||||
|
version "0.5.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz#56082f71b1dc7aac69d83c4285eef39c15d93f56"
|
||||||
|
integrity sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==
|
||||||
|
|
||||||
dom-helpers@^5.0.1:
|
dom-helpers@^5.0.1:
|
||||||
version "5.2.1"
|
version "5.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
|
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
|
||||||
|
@ -6723,6 +6768,11 @@ lru-queue@^0.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
es5-ext "~0.10.2"
|
es5-ext "~0.10.2"
|
||||||
|
|
||||||
|
lz-string@^1.4.4:
|
||||||
|
version "1.4.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
|
||||||
|
integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==
|
||||||
|
|
||||||
make-dir@^2.0.0, make-dir@^2.1.0:
|
make-dir@^2.0.0, make-dir@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
|
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
|
||||||
|
@ -7725,7 +7775,7 @@ pretty-format@^26.0.0, pretty-format@^26.6.2:
|
||||||
ansi-styles "^4.0.0"
|
ansi-styles "^4.0.0"
|
||||||
react-is "^17.0.1"
|
react-is "^17.0.1"
|
||||||
|
|
||||||
pretty-format@^27.5.1:
|
pretty-format@^27.0.2, pretty-format@^27.5.1:
|
||||||
version "27.5.1"
|
version "27.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
|
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
|
||||||
integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
|
integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
|
||||||
|
|
Loading…
Reference in a new issue