mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-09 23:40:05 +00:00
* minor(#16099): when adding team give user option to configure the isJoinable field * chore: add helper text for public team field * test: add test for create team * fix: playwright test
This commit is contained in:
parent
cd5d8dfa06
commit
870bb8c3f2
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Collate.
|
||||||
|
* 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 test, { expect } from '@playwright/test';
|
||||||
|
import { GlobalSettingOptions } from '../../constant/settings';
|
||||||
|
import { redirectToHomePage } from '../../utils/common';
|
||||||
|
import { settingClick } from '../../utils/sidebar';
|
||||||
|
import { createTeam, hardDeleteTeam } from '../../utils/team';
|
||||||
|
|
||||||
|
// use the admin user to login
|
||||||
|
test.use({ storageState: 'playwright/.auth/admin.json' });
|
||||||
|
|
||||||
|
test.describe('Teams Page', () => {
|
||||||
|
test.beforeEach('Visit Home Page', async ({ page }) => {
|
||||||
|
await redirectToHomePage(page);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Create a new public team', async ({ page }) => {
|
||||||
|
await settingClick(page, GlobalSettingOptions.TEAMS);
|
||||||
|
|
||||||
|
await page.waitForSelector('[data-testid="add-team"]');
|
||||||
|
|
||||||
|
await page.getByTestId('add-team').click();
|
||||||
|
|
||||||
|
const publicTeam = await createTeam(page, true);
|
||||||
|
|
||||||
|
await page.getByRole('link', { name: publicTeam.displayName }).click();
|
||||||
|
|
||||||
|
await page
|
||||||
|
.getByTestId('team-details-collapse')
|
||||||
|
.getByTestId('manage-button')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
await expect(page.locator('button[role="switch"]')).toHaveAttribute(
|
||||||
|
'aria-checked',
|
||||||
|
'true'
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.click('body'); // Equivalent to clicking outside
|
||||||
|
|
||||||
|
await hardDeleteTeam(page);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Create a new private team', async ({ page }) => {
|
||||||
|
await settingClick(page, GlobalSettingOptions.TEAMS);
|
||||||
|
|
||||||
|
await page.waitForSelector('[data-testid="add-team"]');
|
||||||
|
|
||||||
|
await page.getByTestId('add-team').click();
|
||||||
|
|
||||||
|
const publicTeam = await createTeam(page);
|
||||||
|
|
||||||
|
await page.getByRole('link', { name: publicTeam.displayName }).click();
|
||||||
|
|
||||||
|
await page
|
||||||
|
.getByTestId('team-details-collapse')
|
||||||
|
.getByTestId('manage-button')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
await expect(page.locator('button[role="switch"]')).toHaveAttribute(
|
||||||
|
'aria-checked',
|
||||||
|
'false'
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.click('body'); // Equivalent to clicking outside
|
||||||
|
|
||||||
|
await hardDeleteTeam(page);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Collate.
|
||||||
|
* 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 { expect, Page } from '@playwright/test';
|
||||||
|
import { uuid } from './common';
|
||||||
|
|
||||||
|
export const createTeam = async (page: Page, isPublic?: boolean) => {
|
||||||
|
const teamData = {
|
||||||
|
name: `pwteam-${uuid()}`,
|
||||||
|
displayName: `PW ${uuid()}`,
|
||||||
|
email: `pwteam${uuid()}@example.com`,
|
||||||
|
description: 'This is a PW team',
|
||||||
|
};
|
||||||
|
|
||||||
|
await page.waitForSelector('[role="dialog"].ant-modal');
|
||||||
|
|
||||||
|
await expect(page.locator('[role="dialog"].ant-modal')).toBeVisible();
|
||||||
|
|
||||||
|
await page.fill('[data-testid="name"]', teamData.name);
|
||||||
|
await page.fill('[data-testid="display-name"]', teamData.displayName);
|
||||||
|
await page.fill('[data-testid="email"]', teamData.email);
|
||||||
|
|
||||||
|
if (isPublic) {
|
||||||
|
await page.getByTestId('isJoinable-switch-button').click();
|
||||||
|
}
|
||||||
|
|
||||||
|
await page
|
||||||
|
.locator('.toastui-editor-md-container > .toastui-editor > .ProseMirror')
|
||||||
|
.isVisible();
|
||||||
|
await page
|
||||||
|
.locator('.toastui-editor-md-container > .toastui-editor > .ProseMirror')
|
||||||
|
.fill(teamData.description);
|
||||||
|
|
||||||
|
const createTeamResponse = page.waitForResponse('/api/v1/teams');
|
||||||
|
|
||||||
|
await page.locator('button[type="submit"]').click();
|
||||||
|
|
||||||
|
await createTeamResponse;
|
||||||
|
|
||||||
|
return teamData;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hardDeleteTeam = async (page: Page) => {
|
||||||
|
await page
|
||||||
|
.getByTestId('team-details-collapse')
|
||||||
|
.getByTestId('manage-button')
|
||||||
|
.click();
|
||||||
|
await page.getByTestId('delete-button').click();
|
||||||
|
|
||||||
|
await page.waitForSelector('[role="dialog"].ant-modal');
|
||||||
|
|
||||||
|
await expect(page.locator('[role="dialog"].ant-modal')).toBeVisible();
|
||||||
|
|
||||||
|
await page.click('[data-testid="hard-delete-option"]');
|
||||||
|
await page.check('[data-testid="hard-delete"]');
|
||||||
|
await page.fill('[data-testid="confirmation-text-input"]', 'DELETE');
|
||||||
|
|
||||||
|
const deleteResponse = page.waitForResponse(
|
||||||
|
'/api/v1/teams/*?hardDelete=true&recursive=true'
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.click('[data-testid="confirm-button"]');
|
||||||
|
|
||||||
|
await deleteResponse;
|
||||||
|
|
||||||
|
await expect(page.locator('.Toastify__toast-body')).toHaveText(
|
||||||
|
/deleted successfully!/
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.click('.Toastify__close-button');
|
||||||
|
};
|
||||||
@ -10,7 +10,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { render } from '@testing-library/react';
|
import { act, fireEvent, render } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { TeamType } from '../../generated/entity/teams/team';
|
import { TeamType } from '../../generated/entity/teams/team';
|
||||||
import AddTeamForm from './AddTeamForm';
|
import AddTeamForm from './AddTeamForm';
|
||||||
@ -38,5 +38,114 @@ describe('AddTeamForm component', () => {
|
|||||||
expect(getByTestId('email')).toBeInTheDocument();
|
expect(getByTestId('email')).toBeInTheDocument();
|
||||||
expect(getByTestId('editor')).toBeInTheDocument();
|
expect(getByTestId('editor')).toBeInTheDocument();
|
||||||
expect(getByTestId('team-selector')).toBeInTheDocument();
|
expect(getByTestId('team-selector')).toBeInTheDocument();
|
||||||
|
expect(getByTestId('isJoinable-switch-button')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call onCancel function when cancel button is clicked', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<AddTeamForm
|
||||||
|
visible
|
||||||
|
isLoading={false}
|
||||||
|
parentTeamType={TeamType.Organization}
|
||||||
|
onCancel={mockCancel}
|
||||||
|
onSave={mockSave}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
getByText('Cancel').click();
|
||||||
|
|
||||||
|
expect(mockCancel).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call onSave function when save button is clicked', async () => {
|
||||||
|
const { getByText, getByTestId } = render(
|
||||||
|
<AddTeamForm
|
||||||
|
visible
|
||||||
|
isLoading={false}
|
||||||
|
parentTeamType={TeamType.Organization}
|
||||||
|
onCancel={mockCancel}
|
||||||
|
onSave={mockSave}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
// input name
|
||||||
|
const nameInput = getByTestId('name');
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.change(nameInput, { target: { value: 'test' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
// input displayName
|
||||||
|
const displayNameInput = getByTestId('display-name');
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.change(displayNameInput, { target: { value: 'Test Team' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
// input email
|
||||||
|
const emailInput = getByTestId('email');
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.change(emailInput, { target: { value: 'testteam@gmail.com' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
// make team joinable
|
||||||
|
const isJoinableSwitch = getByTestId('isJoinable-switch-button');
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(isJoinableSwitch);
|
||||||
|
});
|
||||||
|
|
||||||
|
// save form
|
||||||
|
const saveButton = getByText('label.save');
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockSave).toHaveBeenCalledWith({
|
||||||
|
name: 'test',
|
||||||
|
displayName: 'Test Team',
|
||||||
|
email: 'testteam@gmail.com',
|
||||||
|
description: '',
|
||||||
|
isJoinable: true,
|
||||||
|
teamType: 'Group',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call onSave function when save button is clicked with isJoinable default value', async () => {
|
||||||
|
const { getByText, getByTestId } = render(
|
||||||
|
<AddTeamForm
|
||||||
|
visible
|
||||||
|
isLoading={false}
|
||||||
|
parentTeamType={TeamType.Organization}
|
||||||
|
onCancel={mockCancel}
|
||||||
|
onSave={mockSave}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
// input name
|
||||||
|
const nameInput = getByTestId('name');
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.change(nameInput, { target: { value: 'test' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
// input displayName
|
||||||
|
const displayNameInput = getByTestId('display-name');
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.change(displayNameInput, { target: { value: 'Test Team' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
// save form
|
||||||
|
const saveButton = getByText('label.save');
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockSave).toHaveBeenCalledWith({
|
||||||
|
name: 'test',
|
||||||
|
displayName: 'Test Team',
|
||||||
|
email: undefined,
|
||||||
|
description: '',
|
||||||
|
isJoinable: false,
|
||||||
|
teamType: 'Group',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -21,7 +21,13 @@ import { EditorContentRef } from '../../components/common/RichTextEditor/RichTex
|
|||||||
import { VALIDATION_MESSAGES } from '../../constants/constants';
|
import { VALIDATION_MESSAGES } from '../../constants/constants';
|
||||||
import { ENTITY_NAME_REGEX } from '../../constants/regex.constants';
|
import { ENTITY_NAME_REGEX } from '../../constants/regex.constants';
|
||||||
import { Team, TeamType } from '../../generated/entity/teams/team';
|
import { Team, TeamType } from '../../generated/entity/teams/team';
|
||||||
|
import {
|
||||||
|
FieldProp,
|
||||||
|
FieldTypes,
|
||||||
|
FormItemLayout,
|
||||||
|
} from '../../interface/FormUtils.interface';
|
||||||
import { getTeams } from '../../rest/teamsAPI';
|
import { getTeams } from '../../rest/teamsAPI';
|
||||||
|
import { getField } from '../../utils/formUtils';
|
||||||
import { getTeamOptionsFromType } from '../../utils/TeamUtils';
|
import { getTeamOptionsFromType } from '../../utils/TeamUtils';
|
||||||
import { showErrorToast } from '../../utils/ToastUtils';
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
import { AddTeamFormType } from './AddTeamForm.interface';
|
import { AddTeamFormType } from './AddTeamForm.interface';
|
||||||
@ -65,6 +71,19 @@ const AddTeamForm: React.FC<AddTeamFormType> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isJoinableField: FieldProp = {
|
||||||
|
name: 'isJoinable',
|
||||||
|
label: t('label.public-team'),
|
||||||
|
type: FieldTypes.SWITCH,
|
||||||
|
required: false,
|
||||||
|
props: {
|
||||||
|
'data-testid': 'isJoinable-switch-button',
|
||||||
|
},
|
||||||
|
id: 'isJoinable-switch-button',
|
||||||
|
formItemLayout: FormItemLayout.HORIZONTAL,
|
||||||
|
helperText: t('message.access-to-collaborate'),
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
fetchAllTeams();
|
fetchAllTeams();
|
||||||
@ -82,6 +101,7 @@ const AddTeamForm: React.FC<AddTeamFormType> = ({
|
|||||||
type: 'primary',
|
type: 'primary',
|
||||||
htmlType: 'submit',
|
htmlType: 'submit',
|
||||||
}}
|
}}
|
||||||
|
okText={t('label.save')}
|
||||||
open={visible}
|
open={visible}
|
||||||
title={t('label.add-entity', { entity: t('label.team') })}
|
title={t('label.add-entity', { entity: t('label.team') })}
|
||||||
width={750}
|
width={750}
|
||||||
@ -90,6 +110,7 @@ const AddTeamForm: React.FC<AddTeamFormType> = ({
|
|||||||
id="add-team-form"
|
id="add-team-form"
|
||||||
initialValues={{
|
initialValues={{
|
||||||
teamType: TeamType.Group,
|
teamType: TeamType.Group,
|
||||||
|
isJoinable: false,
|
||||||
}}
|
}}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
name="add-team-nest-messages"
|
name="add-team-nest-messages"
|
||||||
@ -166,6 +187,7 @@ const AddTeamForm: React.FC<AddTeamFormType> = ({
|
|||||||
placeholder={t('message.select-team')}
|
placeholder={t('message.select-team')}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{getField(isJoinableField)}
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t('label.description')}
|
label={t('label.description')}
|
||||||
name="description"
|
name="description"
|
||||||
|
|||||||
@ -268,6 +268,7 @@ const TeamsPage = () => {
|
|||||||
teamType: data.teamType as TeamType,
|
teamType: data.teamType as TeamType,
|
||||||
parents: fqn ? [selectedTeam.id] : undefined,
|
parents: fqn ? [selectedTeam.id] : undefined,
|
||||||
email: data.email || undefined,
|
email: data.email || undefined,
|
||||||
|
isJoinable: data.isJoinable,
|
||||||
};
|
};
|
||||||
const res = await createTeam(teamData);
|
const res = await createTeam(teamData);
|
||||||
if (res) {
|
if (res) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user