Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add unit tests for Dataset #874

Merged
merged 8 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions frontend/setupTests.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { config } from '@vue/test-utils';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import CsgButton from '@/components/shared/CsgButton.vue';
import CsgButton from '@/components/shared/CsgButton.vue';
import SvgIcon from '@/components/shared/SvgIcon.vue';
import FlashMessage from '@/components/shared/FlashMessage.vue';
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
import { createI18n } from 'vue-i18n';
import { createPinia } from 'pinia'
import en from '@/locales/en.js'
import zh from '@/locales/zh.js'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import '@/assets/stylesheets/element-plus/_variables.css'
import '@/assets/stylesheets/markdown.css'
import '@/style.css'

const pinia = createPinia();
const i18n = createI18n({
Expand All @@ -19,16 +24,29 @@ const i18n = createI18n({
}
});

config.global.plugins = [ElementPlus, i18n, pinia];

// register global components
config.global.components = {
SvgIcon,
CsgButton,
FlashMessage,
...ElementPlusIconsVue
};

// gllbal mock
config.global.plugins = [
[ElementPlus, {
locale: zhCn,
}],
i18n,
pinia
];

const DEFAULT_TAGS = []
const CSGHUB_SERVER = 'http://localhost:8080'

config.global.provide = {
defaultTags: DEFAULT_TAGS,
csghubServer: CSGHUB_SERVER,
nameRule: /^(?=.{2,64}$)(?!.*[-_.]{2})[a-zA-Z][a-zA-Z0-9_.-]*[a-zA-Z0-9]+$/
};

// Mock window.location
const mockLocation = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { describe, it, expect, beforeEach } from "vitest";
import { mount } from "@vue/test-utils";
import DatasetRelationsCard from "@/components/datasets/DatasetRelationsCard.vue";
import RepoItem from "@/components/shared/RepoItem.vue";

const createWrapper = (props) => {
return mount(DatasetRelationsCard, {
props: {
namespacePath: 'test/namespace',
datasets: [],
...props
}
});
};

describe("DatasetRelationsCard", () => {
it("mounts correctly", () => {
const wrapper = createWrapper();
expect(wrapper.vm).toBeDefined();
});

it("renders correctly with props", () => {
const datasets = [{
id: 1,
name: 'Dataset 1',
path: 'user/dataset-1',
updated_at: '2024-03-20 10:00:00',
downloads: 100
}, {
id: 2,
name: 'Dataset 2',
path: 'user/dataset-2',
updated_at: '2024-03-20 10:00:00',
downloads: 200
}];

const wrapper = createWrapper({ datasets });

// Test title and count display
expect(wrapper.find('h3').text()).toContain('Associated Datasets2');
expect(wrapper.find('h3 .text-gray-500').text().trim()).toBe('2');

// Test RepoItem components rendering
const repoItems = wrapper.findAllComponents(RepoItem);
expect(repoItems.length).toBe(datasets.length);

// Verify RepoItem props
const firstRepoItem = repoItems[0];
expect(firstRepoItem.props('repo')).toEqual(datasets[0]);
expect(firstRepoItem.props('repoType')).toBe('dataset');
expect(firstRepoItem.props('cardType')).toBe('relations');
});

it("renders correctly with empty datasets", () => {
const wrapper = createWrapper({ datasets: [] });
expect(wrapper.findAllComponents(RepoItem).length).toBe(0);
expect(wrapper.find('h3 .text-gray-500').text().trim()).toBe('0');
});
});
150 changes: 150 additions & 0 deletions frontend/src/components/__tests__/datasets/DatasetSettings.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { describe, it, expect, beforeEach, vi } from "vitest";
import { mount } from "@vue/test-utils";
import DatasetSettings from "@/components/datasets/DatasetSettings.vue";
import { createPinia, setActivePinia } from 'pinia';

// Mock the API response
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 === '/tags') {
return Promise.resolve({
data: {
value: {
data: [
{ name: 'tag1', category: 'industry', scope: 'dataset', show_name: 'Tag 1' },
{ name: 'tag2', category: 'industry', scope: 'dataset', show_name: 'Tag 2' }
]
}
},
error: { value: null }
})
}
return Promise.resolve({
data: { value: null },
error: { value: null }
})
}
})
}));

const createWrapper = (props = {}) => {
return mount(DatasetSettings, {
props: {
path: "test/dataset",
datasetNickname: "Test Dataset",
datasetDesc: "Test Description",
default_branch: "main",
tagList: [],
tags: {
task_tags: [],
other_tags: [],
industry_tags: []
},
...props
},
global: {
plugins: [createPinia()],
mocks: {
$t: (key) => key
}
}
});
};

describe("DatasetSettings", () => {
beforeEach(() => {
setActivePinia(createPinia());
});

it("mounts correctly", () => {
const wrapper = createWrapper();
expect(wrapper.vm).toBeDefined();
});

it("displays dataset path correctly", () => {
const wrapper = createWrapper();
expect(wrapper.find('.bg-gray-50').text()).toBe("test/dataset");
});

it("updates dataset nickname", async () => {
const wrapper = createWrapper();
await wrapper.find('input').setValue('New Dataset Name');
await wrapper.findAll('button').find(btn => btn.text() === 'all.update').trigger('click');
expect(wrapper.vm.theDatasetNickname).toBe('New Dataset Name');
});

it("updates dataset description", async () => {
const wrapper = createWrapper();
const textarea = wrapper.find('textarea');
await textarea.setValue('New Description');
const updateButtons = wrapper.findAll('button');
await updateButtons[1].trigger('click');
expect(wrapper.vm.theDatasetDesc).toBe('New Description');
});

it("handles tag selection correctly", async () => {
const wrapper = createWrapper({
tagList: [{ name: "tag1", show_name: "Tag 1" }]
});
await wrapper.vm.selectTag({ name: "tag1", show_name: "Tag 1" });
expect(wrapper.vm.selectedTags).toHaveLength(1);
});

it("removes tag when close icon is clicked", async () => {
const wrapper = createWrapper();
await wrapper.setData({
selectedTags: [{ name: "tag1", show_name: "Tag 1" }]
});
await wrapper.vm.removeTag("tag1");
expect(wrapper.vm.selectedTags).toHaveLength(0);
});

it.skip("handles visibility change", async () => {
const wrapper = createWrapper();
const select = wrapper.find('.el-select');
await select.trigger('click');
const options = wrapper.findAll('.el-option');
await options[0].trigger('click');
expect(wrapper.vm.visibilityName).toBe('Private');
});

it("validates delete dataset input", async () => {
const wrapper = createWrapper();
const deleteInput = wrapper.findAll('input').at(-1);
await deleteInput.setValue('test/dataset');
const deleteButton = wrapper.find('#confirmDelete');
expect(deleteButton.classes()).toContain('bg-error-600');
});
});
Loading
Loading