diff options
Diffstat (limited to 'spec/frontend/ml/experiment_tracking/routes/candidates')
3 files changed, 86 insertions, 70 deletions
diff --git a/spec/frontend/ml/experiment_tracking/routes/candidates/show/components/candidate_detail_row_spec.js b/spec/frontend/ml/experiment_tracking/routes/candidates/show/components/candidate_detail_row_spec.js index 53dbd796d85..cd252560590 100644 --- a/spec/frontend/ml/experiment_tracking/routes/candidates/show/components/candidate_detail_row_spec.js +++ b/spec/frontend/ml/experiment_tracking/routes/candidates/show/components/candidate_detail_row_spec.js @@ -2,15 +2,14 @@ import { shallowMount } from '@vue/test-utils'; import DetailRow from '~/ml/experiment_tracking/routes/candidates/show/components/candidate_detail_row.vue'; describe('CandidateDetailRow', () => { - const SECTION_LABEL_CELL = 0; - const ROW_LABEL_CELL = 1; - const ROW_VALUE_CELL = 2; + const ROW_LABEL_CELL = 0; + const ROW_VALUE_CELL = 1; let wrapper; const createWrapper = ({ slots = {} } = {}) => { wrapper = shallowMount(DetailRow, { - propsData: { sectionLabel: 'Section', label: 'Item' }, + propsData: { label: 'Item' }, slots, }); }; @@ -19,10 +18,6 @@ describe('CandidateDetailRow', () => { beforeEach(() => createWrapper()); - it('renders section label', () => { - expect(findCellAt(SECTION_LABEL_CELL).text()).toBe('Section'); - }); - it('renders row label', () => { expect(findCellAt(ROW_LABEL_CELL).text()).toBe('Item'); }); diff --git a/spec/frontend/ml/experiment_tracking/routes/candidates/show/ml_candidates_show_spec.js b/spec/frontend/ml/experiment_tracking/routes/candidates/show/ml_candidates_show_spec.js index 0b3b780cb3f..296728af46a 100644 --- a/spec/frontend/ml/experiment_tracking/routes/candidates/show/ml_candidates_show_spec.js +++ b/spec/frontend/ml/experiment_tracking/routes/candidates/show/ml_candidates_show_spec.js @@ -1,32 +1,51 @@ -import { shallowMount } from '@vue/test-utils'; -import { GlAvatarLabeled, GlLink } from '@gitlab/ui'; +import { GlAvatarLabeled, GlLink, GlTableLite } from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import MlCandidatesShow from '~/ml/experiment_tracking/routes/candidates/show'; import DetailRow from '~/ml/experiment_tracking/routes/candidates/show/components/candidate_detail_row.vue'; -import { TITLE_LABEL } from '~/ml/experiment_tracking/routes/candidates/show/translations'; +import { + TITLE_LABEL, + NO_PARAMETERS_MESSAGE, + NO_METRICS_MESSAGE, + NO_METADATA_MESSAGE, + NO_CI_MESSAGE, +} from '~/ml/experiment_tracking/routes/candidates/show/translations'; import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue'; import ModelExperimentsHeader from '~/ml/experiment_tracking/components/model_experiments_header.vue'; +import { stubComponent } from 'helpers/stub_component'; import { newCandidate } from './mock_data'; describe('MlCandidatesShow', () => { let wrapper; const CANDIDATE = newCandidate(); - const USER_ROW = 6; + const USER_ROW = 1; + + const INFO_SECTION = 0; + const CI_SECTION = 1; + const PARAMETER_SECTION = 2; + const METADATA_SECTION = 3; const createWrapper = (createCandidate = () => CANDIDATE) => { - wrapper = shallowMount(MlCandidatesShow, { + wrapper = shallowMountExtended(MlCandidatesShow, { propsData: { candidate: createCandidate() }, + stubs: { + GlTableLite: { ...stubComponent(GlTableLite), props: ['items', 'fields'] }, + }, }); }; const findDeleteButton = () => wrapper.findComponent(DeleteButton); const findHeader = () => wrapper.findComponent(ModelExperimentsHeader); - const findNthDetailRow = (index) => wrapper.findAllComponents(DetailRow).at(index); - const findLinkInNthDetailRow = (index) => findNthDetailRow(index).findComponent(GlLink); - const findSectionLabel = (label) => wrapper.find(`[sectionLabel='${label}']`); + const findSection = (section) => wrapper.findAll('section').at(section); + const findRowInSection = (section, row) => + findSection(section).findAllComponents(DetailRow).at(row); + const findLinkAtRow = (section, rowIndex) => + findRowInSection(section, rowIndex).findComponent(GlLink); + const findNoDataMessage = (label) => wrapper.findByText(label); const findLabel = (label) => wrapper.find(`[label='${label}']`); - const findCiUserDetailRow = () => findNthDetailRow(USER_ROW); + const findCiUserDetailRow = () => findRowInSection(CI_SECTION, USER_ROW); const findCiUserAvatar = () => findCiUserDetailRow().findComponent(GlAvatarLabeled); const findCiUserAvatarNameLink = () => findCiUserAvatar().findComponent(GlLink); + const findMetricsTable = () => wrapper.findComponent(GlTableLite); describe('Header', () => { beforeEach(() => createWrapper()); @@ -50,42 +69,57 @@ describe('MlCandidatesShow', () => { const mrText = `!${CANDIDATE.info.ci_job.merge_request.iid} ${CANDIDATE.info.ci_job.merge_request.title}`; const expectedTable = [ - ['Info', 'ID', CANDIDATE.info.iid], - ['', 'MLflow run ID', CANDIDATE.info.eid], - ['', 'Status', CANDIDATE.info.status], - ['', 'Experiment', CANDIDATE.info.experiment_name], - ['', 'Artifacts', 'Artifacts'], - ['CI', 'Job', CANDIDATE.info.ci_job.name], - ['', 'Triggered by', 'CI User'], - ['', 'Merge request', mrText], - ['Parameters', CANDIDATE.params[0].name, CANDIDATE.params[0].value], - ['', CANDIDATE.params[1].name, CANDIDATE.params[1].value], - ['Metrics', CANDIDATE.metrics[0].name, CANDIDATE.metrics[0].value], - ['', CANDIDATE.metrics[1].name, CANDIDATE.metrics[1].value], - ['Metadata', CANDIDATE.metadata[0].name, CANDIDATE.metadata[0].value], - ['', CANDIDATE.metadata[1].name, CANDIDATE.metadata[1].value], - ].map((row, index) => [index, ...row]); - - it.each(expectedTable)( - 'row %s is created correctly', - (rowIndex, sectionLabel, label, text) => { - const row = findNthDetailRow(rowIndex); - - expect(row.props()).toMatchObject({ sectionLabel, label }); - expect(row.text()).toBe(text); - }, - ); + [INFO_SECTION, 0, 'ID', CANDIDATE.info.iid], + [INFO_SECTION, 1, 'MLflow run ID', CANDIDATE.info.eid], + [INFO_SECTION, 2, 'Status', CANDIDATE.info.status], + [INFO_SECTION, 3, 'Experiment', CANDIDATE.info.experiment_name], + [INFO_SECTION, 4, 'Artifacts', 'Artifacts'], + [CI_SECTION, 0, 'Job', CANDIDATE.info.ci_job.name], + [CI_SECTION, 1, 'Triggered by', 'CI User'], + [CI_SECTION, 2, 'Merge request', mrText], + [PARAMETER_SECTION, 0, CANDIDATE.params[0].name, CANDIDATE.params[0].value], + [PARAMETER_SECTION, 1, CANDIDATE.params[1].name, CANDIDATE.params[1].value], + [METADATA_SECTION, 0, CANDIDATE.metadata[0].name, CANDIDATE.metadata[0].value], + [METADATA_SECTION, 1, CANDIDATE.metadata[1].name, CANDIDATE.metadata[1].value], + ]; + + it.each(expectedTable)('row %s is created correctly', (section, rowIndex, label, text) => { + const row = findRowInSection(section, rowIndex); + + expect(row.props()).toMatchObject({ label }); + expect(row.text()).toBe(text); + }); describe('Table links', () => { const linkRows = [ - [3, CANDIDATE.info.path_to_experiment], - [4, CANDIDATE.info.path_to_artifact], - [5, CANDIDATE.info.ci_job.path], - [7, CANDIDATE.info.ci_job.merge_request.path], + [INFO_SECTION, 3, CANDIDATE.info.path_to_experiment], + [INFO_SECTION, 4, CANDIDATE.info.path_to_artifact], + [CI_SECTION, 0, CANDIDATE.info.ci_job.path], + [CI_SECTION, 2, CANDIDATE.info.ci_job.merge_request.path], ]; - it.each(linkRows)('row %s is created correctly', (rowIndex, href) => { - expect(findLinkInNthDetailRow(rowIndex).attributes().href).toBe(href); + it.each(linkRows)('row %s is created correctly', (section, rowIndex, href) => { + expect(findLinkAtRow(section, rowIndex).attributes().href).toBe(href); + }); + }); + + describe('Metrics table', () => { + it('computes metrics table items correctly', () => { + expect(findMetricsTable().props('items')).toEqual([ + { name: 'AUC', 0: '.55' }, + { name: 'Accuracy', 1: '.99', 2: '.98', 3: '.97' }, + { name: 'F1', 3: '.1' }, + ]); + }); + + it('computes metrics table fields correctly', () => { + expect(findMetricsTable().props('fields')).toEqual([ + expect.objectContaining({ key: 'name', label: 'Metric' }), + expect.objectContaining({ key: '0', label: 'Step 0' }), + expect.objectContaining({ key: '1', label: 'Step 1' }), + expect.objectContaining({ key: '2', label: 'Step 2' }), + expect.objectContaining({ key: '3', label: 'Step 3' }), + ]); }); }); @@ -105,22 +139,6 @@ describe('MlCandidatesShow', () => { expect(nameLink.text()).toEqual('CI User'); }); }); - - it('does not render params', () => { - expect(findSectionLabel('Parameters').exists()).toBe(true); - }); - - it('renders all conditional rows', () => { - // This is a bit of a duplicated test from the above table test, but having this makes sure that the - // tests that test the negatives are implemented correctly - expect(findLabel('Artifacts').exists()).toBe(true); - expect(findSectionLabel('Parameters').exists()).toBe(true); - expect(findSectionLabel('Metadata').exists()).toBe(true); - expect(findSectionLabel('Metrics').exists()).toBe(true); - expect(findSectionLabel('CI').exists()).toBe(true); - expect(findLabel('Merge request').exists()).toBe(true); - expect(findLabel('Triggered by').exists()).toBe(true); - }); }); describe('No artifact path', () => { @@ -150,19 +168,19 @@ describe('MlCandidatesShow', () => { ); it('does not render params', () => { - expect(findSectionLabel('Parameters').exists()).toBe(false); + expect(findNoDataMessage(NO_PARAMETERS_MESSAGE).exists()).toBe(true); }); it('does not render metadata', () => { - expect(findSectionLabel('Metadata').exists()).toBe(false); + expect(findNoDataMessage(NO_METADATA_MESSAGE).exists()).toBe(true); }); it('does not render metrics', () => { - expect(findSectionLabel('Metrics').exists()).toBe(false); + expect(findNoDataMessage(NO_METRICS_MESSAGE).exists()).toBe(true); }); it('does not render CI info', () => { - expect(findSectionLabel('CI').exists()).toBe(false); + expect(findNoDataMessage(NO_CI_MESSAGE).exists()).toBe(true); }); }); diff --git a/spec/frontend/ml/experiment_tracking/routes/candidates/show/mock_data.js b/spec/frontend/ml/experiment_tracking/routes/candidates/show/mock_data.js index 3fbcf122997..4ea23ed2513 100644 --- a/spec/frontend/ml/experiment_tracking/routes/candidates/show/mock_data.js +++ b/spec/frontend/ml/experiment_tracking/routes/candidates/show/mock_data.js @@ -4,8 +4,11 @@ export const newCandidate = () => ({ { name: 'MaxDepth', value: '3' }, ], metrics: [ - { name: 'AUC', value: '.55' }, - { name: 'Accuracy', value: '.99' }, + { name: 'AUC', value: '.55', step: 0 }, + { name: 'Accuracy', value: '.99', step: 1 }, + { name: 'Accuracy', value: '.98', step: 2 }, + { name: 'Accuracy', value: '.97', step: 3 }, + { name: 'F1', value: '.1', step: 3 }, ], metadata: [ { name: 'FileName', value: 'test.py' }, |