From 7c97fef264b7c0d68ac18e305454143c5a0b357d Mon Sep 17 00:00:00 2001 From: "minghao.yang" Date: Mon, 30 Dec 2024 15:02:31 +0800 Subject: [PATCH 1/6] NewOrganization test --- .../organizations/NewOrganization.spec.js | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 frontend/src/components/__tests__/organizations/NewOrganization.spec.js diff --git a/frontend/src/components/__tests__/organizations/NewOrganization.spec.js b/frontend/src/components/__tests__/organizations/NewOrganization.spec.js new file mode 100644 index 000000000..843ece5aa --- /dev/null +++ b/frontend/src/components/__tests__/organizations/NewOrganization.spec.js @@ -0,0 +1,80 @@ +import { describe, it, expect, vi } from 'vitest' +import { mount } from '@vue/test-utils' +import NewOrganization from '@/components/organizations/NewOrganization.vue' + +const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) + +const createWrapper = (props) => { + return mount(NewOrganization, { + global: { + provide: { + nameRule: /^[a-zA-Z][a-zA-Z0-9-_.]*[a-zA-Z0-9]$/ + } + }, + props: { + ...props + } + }) +} + +const triggerFormButton = async (wrapper) => { + const button = wrapper.findComponent({ name: 'CsgButton' }) + await button.trigger('click') + await delay(500) + await wrapper.vm.$nextTick() +} + +vi.mock('../../../stores/UserStore', () => ({ + default: () => ({ + username: 'testuser', + orgs: [{ path: 'testorg' }] + }) +})) + +vi.mock('../../../packs/useFetchApi', () => ({ + default: () => ({ + post: () => ({ + json: () => + Promise.resolve({ + data: { value: { data: { name: 'testorg' } } }, + error: { value: null } + }) + }) + }) +})) + +describe('NewOrganization', () => { + describe('mount', async () => { + it('mounts correctly', () => { + const wrapper = createWrapper() + expect(wrapper.exists()).toBe(true) + }) + }) + + describe('form validation', () => { + it('validates required fields', async () => { + const wrapper = createWrapper() + await triggerFormButton(wrapper) + const formErrors = wrapper.findAll('.el-form-item__error') + expect(formErrors.length).toBeGreaterThan(0) + }) + }) + + describe('form submission', async () => { + it('shows success message on successful submission', async () => { + const wrapper = createWrapper() + wrapper.vm.dataForm = { + homepage:'https://test.com"', + logo:'https://opencsg-test.oss-cn-beijing.aliyuncs.com/org_logo/d85a3db4-dd51-47a7-919c-2308c7ff4b6b', + owner: 'testuser', + name: 'testorg', + nickname: 'valid-org', + org_type: '企业', + } + await wrapper.vm.$nextTick() + await triggerFormButton(wrapper) + await new Promise(resolve => setTimeout(resolve, 500)); + expect(window.location.href).toBe('/organizations/testorg') + }) + }) +}) From 4f7193b2590e8998cc010ad2b76beedc52e549ec Mon Sep 17 00:00:00 2001 From: "minghao.yang" Date: Mon, 30 Dec 2024 15:03:13 +0800 Subject: [PATCH 2/6] OrganizationSettings test --- .../OrganizationSettings.spec.js | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js diff --git a/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js b/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js new file mode 100644 index 000000000..095c93702 --- /dev/null +++ b/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js @@ -0,0 +1,139 @@ +import { describe, it, expect, vi } from 'vitest' +import { mount } from '@vue/test-utils' +import OrganizationSettings from '@/components/organizations/OrganizationSettings.vue' +import OrganizationEdit from '@/components/organizations/OrganizationEdit.vue' +import OrganizationMembers from '@/components/organizations/OrganizationMembers.vue' +import Menu from '@/components/organizations/Menu.vue' + +const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) + +const createWrapper = (props) => { + return mount(OrganizationSettings, { + global: { + provide: { + verified: false + } + }, + props: { + name: 'testorg', + action: 'edit', + ...props + } + }) +} + +vi.mock('../../../stores/UserStore', () => ({ + default: () => ({ + username: 'testuser', + orgs: [{ path: 'testorg' }] + }) +})) + +vi.mock('@/packs/useFetchApi', () => ({ + default: (url) => ({ + post: () => ({ + json: () => + Promise.resolve({ + data: { value: { msg: 'Success' } }, + error: { value: null } + }) + }), + put: () => ({ + json: () => + Promise.resolve({ + data: { value: { msg: 'Success' } }, + error: { value: null } + }) + }), + delete: () => ({ + json: () => + Promise.resolve({ + data: { value: null }, + error: { value: null } + }) + }), + get: () => ({ + json: () => + Promise.resolve({ + data: { + value: { + data: { + content: btoa('test content'), + sha: 'test-sha' + } + } + }, + error: { value: null } + }) + }), + json: () => { + if (url === '/organization/testorg') { + return Promise.resolve({ + data: { + value: { + data: { + path: 'testorg', + name: 'testorg', + homepage: 'https://baiud.com', + logo: 'https://opencsg-test.oss-cn-beijing.aliyuncs.com/org_logo/072d3ec8-c5c1-4e36-b268-05fd2a6747ee', + org_type: '社区组织', + verified: false + } + } + }, + error: { value: null } + }) + } + if (url === '/organization/testorg/members/testuser') { + return Promise.resolve({ + data: { + value: { + data: 'admin' + } + }, + error: { value: null } + }) + } + return Promise.resolve({ + data: { value: null }, + error: { value: null } + }) + } + }) +})) + +describe('NewOrganization', () => { + describe('mount', async () => { + it('mounts correctly', async () => { + const wrapper = createWrapper() + expect(wrapper.exists()).toBe(true) + await wrapper.vm.$nextTick() + expect(wrapper.vm.organization).toEqual( + expect.objectContaining({ + name: 'testorg', + nickname: 'testorg', + homepage: 'https://baiud.com', + logo: 'https://opencsg-test.oss-cn-beijing.aliyuncs.com/org_logo/072d3ec8-c5c1-4e36-b268-05fd2a6747ee', + org_type: '社区组织', + verified: false + }) + ) + await wrapper.vm.currentUserRole() + expect(wrapper.vm.role).toBe('admin') + }) + it('renders Menu component', () => { + const wrapper = createWrapper() + const menu = wrapper.findComponent(Menu) + expect(menu.exists()).toBe(true) + }) + it('renders OrganizationEdit when action is edit', () => { + const wrapper = createWrapper() + expect(wrapper.findComponent(OrganizationEdit).exists()).toBe(true) + }) + + it('does not render OrganizationMembers when action is not members', () => { + const wrapper = createWrapper() + expect(wrapper.findComponent(OrganizationMembers).exists()).toBe(false) + }) + }) +}) From 19afb8470bc600370609968e907656adb59791ce Mon Sep 17 00:00:00 2001 From: "minghao.yang" Date: Tue, 31 Dec 2024 16:09:38 +0800 Subject: [PATCH 3/6] Update test --- .../components/__tests__/organizations/NewOrganization.spec.js | 2 +- .../__tests__/organizations/OrganizationSettings.spec.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/components/__tests__/organizations/NewOrganization.spec.js b/frontend/src/components/__tests__/organizations/NewOrganization.spec.js index 843ece5aa..f3dab04e5 100644 --- a/frontend/src/components/__tests__/organizations/NewOrganization.spec.js +++ b/frontend/src/components/__tests__/organizations/NewOrganization.spec.js @@ -31,7 +31,7 @@ vi.mock('../../../stores/UserStore', () => ({ }) })) -vi.mock('../../../packs/useFetchApi', () => ({ +vi.mock('@/packs/useFetchApi', () => ({ default: () => ({ post: () => ({ json: () => diff --git a/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js b/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js index 095c93702..5dc471028 100644 --- a/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js +++ b/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js @@ -5,8 +5,6 @@ import OrganizationEdit from '@/components/organizations/OrganizationEdit.vue' import OrganizationMembers from '@/components/organizations/OrganizationMembers.vue' import Menu from '@/components/organizations/Menu.vue' -const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) - const createWrapper = (props) => { return mount(OrganizationSettings, { global: { From a4597222c08e50a440dd6238a532adcdfbdd62ad Mon Sep 17 00:00:00 2001 From: "minghao.yang" Date: Tue, 31 Dec 2024 16:09:50 +0800 Subject: [PATCH 4/6] OrganizationDetail test --- .../organizations/OrganizationDetail.spec.js | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 frontend/src/components/__tests__/organizations/OrganizationDetail.spec.js diff --git a/frontend/src/components/__tests__/organizations/OrganizationDetail.spec.js b/frontend/src/components/__tests__/organizations/OrganizationDetail.spec.js new file mode 100644 index 000000000..6157b5e8a --- /dev/null +++ b/frontend/src/components/__tests__/organizations/OrganizationDetail.spec.js @@ -0,0 +1,154 @@ +import { describe, it, expect, vi } from 'vitest' +import { mount } from '@vue/test-utils' +import OrganizationDetail from '@/components/organizations/OrganizationDetail.vue' + +const createWrapper = (props) => { + return mount(OrganizationDetail, { + global: { + provide: { + verified: false + } + }, + props: { + name: 'testorg', + ...props + } + }) +} + +vi.mock('../../../stores/UserStore', () => ({ + default: () => ({ + username: 'testuser', + orgs: [{ path: 'testorg' }] + }) +})) + +vi.mock('@/packs/useFetchApi', () => ({ + default: (url) => ({ + post: () => ({ + json: () => + Promise.resolve({ + data: { value: { msg: 'Success' } }, + error: { value: null } + }) + }), + put: () => ({ + json: () => + Promise.resolve({ + data: { value: { msg: 'Success' } }, + error: { value: null } + }) + }), + delete: () => ({ + json: () => + Promise.resolve({ + data: { value: null }, + error: { value: null } + }) + }), + get: () => ({ + json: () => + Promise.resolve({ + data: { + value: { + data: { + content: btoa('test content'), + sha: 'test-sha' + } + } + }, + error: { value: null } + }) + }), + json: () => { + console.log(url) + if (url === '/organization/testorg') { + return Promise.resolve({ + data: { + value: { + data: { + path: 'testorg', + name: 'testorg', + homepage: 'https://baiud.com', + logo: 'https://opencsg-test.oss-cn-beijing.aliyuncs.com/org_logo/072d3ec8-c5c1-4e36-b268-05fd2a6747ee', + org_type: '社区组织', + verified: false + } + } + }, + error: { value: null } + }) + } + if (url === '/organization/testorg/members') { + return Promise.resolve({ + data: { + value: { + data: { + data: [ + { + username: 'testuser', + nickname: 'testuser', + uuid: '75496af6-3004-4e96-ad7e-07ff999b40fc', + avatar: + 'https://opencsg-test.oss-cn-beijing.aliyuncs.com/comment/10fe27da-4ebe-4713-aa7d-2daafdf9851c', + role: 'admin', + last_login_at: '2024-12-30 02:55:43' + } + ], + total: 1 + } + } + }, + error: { value: null } + }) + } + if (url === '/organization/testorg/members/testuser') { + return Promise.resolve({ + data: { + value: { + data: 'admin' + } + }, + error: { value: null } + }) + } + return Promise.resolve({ + data: { value: { data: null } }, + error: { value: null } + }) + } + }) +})) + +describe('OrganizationDetail', () => { + describe('mount', async () => { + it('mounts correctly', async () => { + const wrapper = createWrapper() + expect(wrapper.exists()).toBe(true) + await wrapper.vm.$nextTick() + console.log(wrapper.vm.organizationData) + expect(wrapper.vm.organizationData).toEqual( + expect.objectContaining({ + name: 'testorg', + nickname: 'testorg', + verified: false, + avatar: + 'https://opencsg-test.oss-cn-beijing.aliyuncs.com/org_logo/072d3ec8-c5c1-4e36-b268-05fd2a6747ee' + }) + ) + expect(wrapper.vm.membersList).toEqual([ + { + username: 'testuser', + nickname: 'testuser', + role: 'admin', + last_login_at: '2024-12-30 02:55:43', + uuid: '75496af6-3004-4e96-ad7e-07ff999b40fc', + avatar: + 'https://opencsg-test.oss-cn-beijing.aliyuncs.com/comment/10fe27da-4ebe-4713-aa7d-2daafdf9851c' + } + ]) + await wrapper.vm.currentUserRole() + expect(wrapper.vm.role).toBe('admin') + }) + }) +}) From b4d44a2fd0ac88c9c3189263b476daa6bd9252ad Mon Sep 17 00:00:00 2001 From: Hiveer Date: Mon, 6 Jan 2025 09:30:43 +0800 Subject: [PATCH 5/6] Code refactor --- .../organizations/NewOrganization.spec.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/__tests__/organizations/NewOrganization.spec.js b/frontend/src/components/__tests__/organizations/NewOrganization.spec.js index f3dab04e5..75fd95606 100644 --- a/frontend/src/components/__tests__/organizations/NewOrganization.spec.js +++ b/frontend/src/components/__tests__/organizations/NewOrganization.spec.js @@ -2,8 +2,6 @@ import { describe, it, expect, vi } from 'vitest' import { mount } from '@vue/test-utils' import NewOrganization from '@/components/organizations/NewOrganization.vue' -const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) - const createWrapper = (props) => { return mount(NewOrganization, { global: { @@ -17,11 +15,13 @@ const createWrapper = (props) => { }) } -const triggerFormButton = async (wrapper) => { +const triggerFormButton = (wrapper) => { const button = wrapper.findComponent({ name: 'CsgButton' }) - await button.trigger('click') - await delay(500) - await wrapper.vm.$nextTick() + button.trigger('click') + // here in the true component button click will trigger an async request and will take some time + // but the test code will not wait for the async function end and will go to next step to do the check + // if we do not wait some time here, the test will failed + return new Promise((resolve) => { setTimeout(resolve, 1000) }) } vi.mock('../../../stores/UserStore', () => ({ @@ -60,7 +60,7 @@ describe('NewOrganization', () => { }) }) - describe('form submission', async () => { + describe('form submission', () => { it('shows success message on successful submission', async () => { const wrapper = createWrapper() wrapper.vm.dataForm = { @@ -73,7 +73,6 @@ describe('NewOrganization', () => { } await wrapper.vm.$nextTick() await triggerFormButton(wrapper) - await new Promise(resolve => setTimeout(resolve, 500)); expect(window.location.href).toBe('/organizations/testorg') }) }) From 900b341bf5aab1dd18e7e7630287c8dc5261ad4c Mon Sep 17 00:00:00 2001 From: Hiveer Date: Mon, 6 Jan 2025 09:57:39 +0800 Subject: [PATCH 6/6] Code refactor --- .../organizations/OrganizationDetail.spec.js | 38 +------------------ .../OrganizationSettings.spec.js | 2 +- .../organizations/OrganizationDetail.vue | 3 -- 3 files changed, 2 insertions(+), 41 deletions(-) diff --git a/frontend/src/components/__tests__/organizations/OrganizationDetail.spec.js b/frontend/src/components/__tests__/organizations/OrganizationDetail.spec.js index 6157b5e8a..bbde819ad 100644 --- a/frontend/src/components/__tests__/organizations/OrganizationDetail.spec.js +++ b/frontend/src/components/__tests__/organizations/OrganizationDetail.spec.js @@ -25,41 +25,6 @@ vi.mock('../../../stores/UserStore', () => ({ vi.mock('@/packs/useFetchApi', () => ({ default: (url) => ({ - post: () => ({ - json: () => - Promise.resolve({ - data: { value: { msg: 'Success' } }, - error: { value: null } - }) - }), - put: () => ({ - json: () => - Promise.resolve({ - data: { value: { msg: 'Success' } }, - error: { value: null } - }) - }), - delete: () => ({ - json: () => - Promise.resolve({ - data: { value: null }, - error: { value: null } - }) - }), - get: () => ({ - json: () => - Promise.resolve({ - data: { - value: { - data: { - content: btoa('test content'), - sha: 'test-sha' - } - } - }, - error: { value: null } - }) - }), json: () => { console.log(url) if (url === '/organization/testorg') { @@ -121,12 +86,11 @@ vi.mock('@/packs/useFetchApi', () => ({ })) describe('OrganizationDetail', () => { - describe('mount', async () => { + describe('mount', () => { it('mounts correctly', async () => { const wrapper = createWrapper() expect(wrapper.exists()).toBe(true) await wrapper.vm.$nextTick() - console.log(wrapper.vm.organizationData) expect(wrapper.vm.organizationData).toEqual( expect.objectContaining({ name: 'testorg', diff --git a/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js b/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js index 5dc471028..be4a79278 100644 --- a/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js +++ b/frontend/src/components/__tests__/organizations/OrganizationSettings.spec.js @@ -100,7 +100,7 @@ vi.mock('@/packs/useFetchApi', () => ({ }) })) -describe('NewOrganization', () => { +describe('OrganizationSettings', () => { describe('mount', async () => { it('mounts correctly', async () => { const wrapper = createWrapper() diff --git a/frontend/src/components/organizations/OrganizationDetail.vue b/frontend/src/components/organizations/OrganizationDetail.vue index ce662fa8e..aa9f0e16f 100644 --- a/frontend/src/components/organizations/OrganizationDetail.vue +++ b/frontend/src/components/organizations/OrganizationDetail.vue @@ -109,7 +109,6 @@ import { ref, onMounted, watch } from 'vue' import InviteMember from './InviteMember.vue' import ProfileRepoList from '../shared/ProfileRepoList.vue' - import { useCookies } from 'vue3-cookies' import useFetchApi from '../../packs/useFetchApi' import { ElMessage } from 'element-plus' import useUserStore from '../../stores/UserStore' @@ -126,8 +125,6 @@ }) const membersList = ref([]) - const { cookies } = useCookies() - const userStore = useUserStore() const role = ref('')