Skip to content
Snippets Groups Projects
Unverified Commit 88e5219b authored by Tiago Evangelista Pinto's avatar Tiago Evangelista Pinto Committed by GitHub
Browse files

fix(UiKit): Modal validation not working (#32679)

parent 35985d7e
No related branches found
No related tags found
No related merge requests found
---
"@rocket.chat/meteor": patch
"@rocket.chat/fuselage-ui-kit": patch
---
Fix validations from "UiKit" modal component
......@@ -14,6 +14,7 @@ type UseModalContextValueParams = {
blockId?: string | undefined;
};
};
errors?: { [field: string]: string }[] | { [field: string]: string };
updateValues: Dispatch<{
actionId: string;
payload: {
......@@ -25,7 +26,7 @@ type UseModalContextValueParams = {
type UseModalContextValueReturn = ContextType<typeof UiKitContext>;
export const useModalContextValue = ({ view, values, updateValues }: UseModalContextValueParams): UseModalContextValueReturn => {
export const useModalContextValue = ({ view, errors, values, updateValues }: UseModalContextValueParams): UseModalContextValueReturn => {
const actionManager = useUiKitActionManager();
const emitInteraction = useMemo(() => actionManager.emitInteraction.bind(actionManager), [actionManager]);
......@@ -62,6 +63,7 @@ export const useModalContextValue = ({ view, values, updateValues }: UseModalCon
});
},
...view,
errors,
values,
viewId: view.id,
};
......
......@@ -20,7 +20,7 @@ type UiKitModalProps = {
const UiKitModal = ({ initialView }: UiKitModalProps) => {
const actionManager = useUiKitActionManager();
const { view, errors, values, updateValues, state } = useUiKitView(initialView);
const contextValue = useModalContextValue({ view, values, updateValues });
const contextValue = useModalContextValue({ view, errors, values, updateValues });
const handleSubmit = useEffectEvent((e: FormEvent) => {
preventSyntheticEvent(e);
......
import { Users } from './fixtures/userStates';
import { HomeChannel } from './page-objects';
import { createTargetChannel } from './utils/create-target-channel';
import { test, expect } from './utils/test';
import { Users } from '../fixtures/userStates';
import { HomeChannel } from '../page-objects';
import { createTargetChannel } from '../utils/create-target-channel';
import { test, expect } from '../utils/test';
test.use({ storageState: Users.admin.state });
......
import { Users } from './fixtures/userStates';
import { HomeChannel } from './page-objects';
import { expect, test } from './utils/test';
import type { Page } from '@playwright/test';
import { Users } from '../fixtures/userStates';
import { HomeChannel } from '../page-objects';
import { expect, test } from '../utils/test';
test.use({ storageState: Users.user1.state });
test.describe.serial('Apps', () => {
test.describe.serial('Apps > ContextualBar', () => {
let poHomeChannel: HomeChannel;
test.beforeEach(async ({ page }) => {
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
poHomeChannel = new HomeChannel(page);
await page.goto('/home');
await poHomeChannel.sidenav.openChat('general');
});
test.afterAll(async () => {
await page.close();
});
test('expect allow user open app contextualbar', async () => {
await poHomeChannel.content.dispatchSlashCommand('/contextualbar');
await expect(poHomeChannel.btnContextualbarClose).toBeVisible();
});
test('expect app contextualbar to be closed', async () => {
await poHomeChannel.content.dispatchSlashCommand('/contextualbar');
await poHomeChannel.btnContextualbarClose.click();
await expect(poHomeChannel.btnContextualbarClose).toBeHidden();
});
......
import type { Page } from '@playwright/test';
import { Users } from '../fixtures/userStates';
import { HomeChannel } from '../page-objects';
import { Modal } from '../page-objects/modal';
import { expect, test } from '../utils/test';
test.use({ storageState: Users.user1.state });
test.describe.serial('Apps > ContextualBar', () => {
let poHomeChannel: HomeChannel;
let poModal: Modal;
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
poHomeChannel = new HomeChannel(page);
poModal = new Modal(page);
await page.goto('/home');
await poHomeChannel.sidenav.openChat('general');
});
test.afterAll(async () => {
await page.close();
});
test('expect allow user open app modal', async () => {
await poHomeChannel.content.dispatchSlashCommand('/modal');
await expect(poModal.btnModalSubmit).toBeVisible();
});
test('expect validation error message appears in app modal', async () => {
await expect(poModal.textInput).toBeVisible();
await poModal.btnModalSubmit.click();
await expect(poModal.textInputErrorMessage).toBeVisible();
});
test("expect validation error message don't appears in app modal", async () => {
await poModal.textInput.fill('something');
await poModal.btnModalSubmit.click();
await expect(poModal.textInputErrorMessage).not.toBeVisible();
});
});
......@@ -3,7 +3,7 @@ import { request } from '@playwright/test';
import { BASE_API_URL, BASE_URL } from '../config/constants';
import { Users } from './userStates';
const APP_URL = 'https://github.com/RocketChat/Apps.RocketChat.Tester/blob/master/dist/appsrocketchattester_0.0.5.zip?raw=true';
const APP_URL = 'https://github.com/RocketChat/Apps.RocketChat.Tester/blob/master/dist/appsrocketchattester_0.1.0.zip?raw=true';
export default async function insertApp(): Promise<void> {
const api = await request.newContext();
......
import type { Locator, Page } from '@playwright/test';
export class Modal {
protected readonly page: Page;
constructor(page: Page) {
this.page = page;
}
get textInput(): Locator {
return this.page.locator('[name="modal_input"]');
}
get textInputErrorMessage(): Locator {
return this.page.getByText('Validation failed');
}
get btnModalSubmit(): Locator {
return this.page.locator('role=button[name="Submit"]');
}
}
......@@ -26,7 +26,7 @@ type UiKitContextValue = {
event: Parameters<React.MouseEventHandler<HTMLElement>>[0]
) => Promise<void> | void;
appId?: string;
errors?: Record<string, string>;
errors?: { [field: string]: string }[] | { [field: string]: string };
values: Record<ActionId, { value: unknown } | undefined>;
viewId?: string;
rid?: string;
......
......@@ -57,7 +57,11 @@ export const useUiKitState = <TElement extends UiKit.ActionableElement>(
const { values, errors } = useContext(UiKitContext);
const _value = getElementValueFromState(actionId, values, initialValue);
const error = errors?.[actionId];
const error = Array.isArray(errors)
? errors.find((error) =>
Object.keys(error).find((key) => key === actionId)
)?.[actionId]
: errors?.[actionId];
const [value, setValue] = useSafely(useState(_value));
const [loading, setLoading] = useSafely(useState(false));
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment