Skip to content

Commit

Permalink
Merge pull request #11833 from EshaanAgg/vtl
Browse files Browse the repository at this point in the history
Introduce Vue Testing Library
  • Loading branch information
MisRob authored Feb 20, 2024
2 parents 4f12ce5 + 2da09b7 commit 0a25fd5
Show file tree
Hide file tree
Showing 13 changed files with 400 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<KIcon
v-if="correct && diff >= 1"
data-testid="correct-icon"
:style="{ fill: $themeTokens.correct }"
icon="plus"
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>

<span v-if="text">{{ text }}</span>
<span v-if="text" data-testid="attempt-text-diff">{{ text }}</span>

</template>

Expand Down
6 changes: 5 additions & 1 deletion kolibri/core/assets/src/views/ExamReport/TriesOverview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
{{ coreString('statusLabel') }}
</th>
<td>
<ProgressIcon class="svg-icon" :progress="progress" />
<ProgressIcon
class="svg-icon"
:progress="progress"
:data-testid="`progress-icon-${progress}`"
/>
<template v-if="complete">
{{ coreString('completedLabel') }}
</template>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { render, screen } from '@testing-library/vue';
import '@testing-library/jest-dom';
import VueRouter from 'vue-router';
import { themeTokens } from 'kolibri-design-system/lib/styles/theme';
import AttemptIconDiff from '../AttemptIconDiff.vue';

const successThemeColor = themeTokens().correct;

// Helper function to render the component with some default props
const renderComponent = props => {
return render(AttemptIconDiff, {
props: {
correct: 1,
diff: 1,
...props,
},
routes: new VueRouter(),
});
};

describe('AttemptIconDiff', () => {
test('renders KIcon with correct styles when correct and diff conditions are met', () => {
renderComponent();

const kIcon = screen.getByTestId('correct-icon');
expect(kIcon).toBeInTheDocument();
expect(kIcon).toHaveStyle({ fill: successThemeColor });
});

test('does not render KIcon when correct condition is not met', () => {
renderComponent({ correct: 0 });
expect(screen.queryByTestId('correct-icon')).not.toBeInTheDocument();
});

test('does not render KIcon when diff condition is not met', () => {
renderComponent({ diff: 0 });
expect(screen.queryByTestId('k-icon')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { render, screen } from '@testing-library/vue';
import '@testing-library/jest-dom';
import VueRouter from 'vue-router';
import AttemptTextDiff from '../AttemptTextDiff.vue';

const renderComponent = props => {
return render(AttemptTextDiff, {
routes: new VueRouter(),
props,
store: {
getters: {
currentUserId: () => 'mockUser1',
},
},
});
};

const testCases = [
{
caseName: 'Second Person Perspective: Answer Improved',
correct: 1,
diff: 1,
userId: 'mockUser1',
expectedMessage: 'You improved your incorrect answer from the previous attempt',
},
{
caseName: 'Second Person Perspective: Incorrect Answer',
correct: 0,
diff: 0,
userId: 'mockUser1',
expectedMessage: 'You also answered this incorrectly on the previous attempt',
},
{
caseName: 'Second Person Perspective: Correct Answer',
correct: 0,
diff: -1,
userId: 'mockUser1',
expectedMessage: 'You answered this correctly on the previous attempt',
},
{
caseName: 'Third Person Perspective: Answer Improved',
correct: 1,
diff: 1,
userId: 'mockUser2',
expectedMessage: 'Learner improved their incorrect answer from the previous attempt',
},
{
caseName: 'Third Person Perspective: Incorrect Answer',
correct: 0,
diff: 0,
userId: 'mockUser2',
expectedMessage: 'Learner also answered this incorrectly on the previous attempt',
},
{
caseName: 'Third Person Perspective: Correct Answer',
correct: 0,
diff: -1,
userId: 'mockUser2',
expectedMessage: 'Learner answered this correctly on the previous attempt',
},
];

describe('AttemptTextDiff', () => {
testCases.forEach(({ caseName, correct, diff, userId, expectedMessage }) => {
test(caseName, () => {
renderComponent({ correct, diff, userId });
expect(screen.getByText(expectedMessage)).toBeInTheDocument();
});
});

test('No text is shown when the props are invalid', () => {
renderComponent({ correct: 1, diff: 0, userId: 'mockUser1' });
expect(screen.queryByTestId('attempt-text-diff')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { render, screen } from '@testing-library/vue';
import '@testing-library/jest-dom';
import VueRouter from 'vue-router';
import TriesOverview from '../TriesOverview.vue';
import * as tryValidatorModule from '../utils';

// Mock the tryValidator namespace as the same is used in the component
// eslint-disable-next-line import/namespace
tryValidatorModule.tryValidator = jest.fn(() => true);

// Helper function to render the component with some default props
const renderComponent = props => {
const commonCoreStrings = {
methods: {
coreString: x => x,
},
};

const defaultProps = {
pastTries: [],
totalQuestions: 20,
suggestedTime: 240,
...props,
};

return render(TriesOverview, {
props: {
...defaultProps,
...props,
},
routes: new VueRouter(),
mixins: [commonCoreStrings],
});
};

describe('TriesOverview', () => {
describe('Test the progress icon and label', () => {
test('renders progress icon and completed label when there is a completed try', () => {
renderComponent({
pastTries: [
{
id: '1',
completion_timestamp: 100,
},
],
});

expect(screen.getByTestId('progress-icon-1')).toBeInTheDocument();
expect(screen.getByText('completedLabel')).toBeInTheDocument();
});

test('renders progress icon and in-progress label when there is an in-progress try', () => {
renderComponent({
pastTries: [{ id: '2' }],
});

expect(screen.getByTestId('progress-icon-0.5')).toBeInTheDocument();
expect(screen.getByText('inProgressLabel')).toBeInTheDocument();
});

test('renders progress icon and not started label when there are no past tries', () => {
renderComponent();

expect(screen.getByTestId('progress-icon-0')).toBeInTheDocument();
expect(screen.getByText('notStartedLabel')).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ describe('Search side bar', () => {
const wrapper = createWrapper();
wrapper.vm.focusOnInput();
const elementThatIsFocused = document.activeElement;
expect(elementThatIsFocused.classList.contains('search-input')).toBe(true);
expect(elementThatIsFocused).toHaveClass('search-input');
});
});
6 changes: 3 additions & 3 deletions kolibri/plugins/epub_viewer/assets/tests/TopBar.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@ describe('Top bar', () => {
const wrapper = createWrapper();
wrapper.vm.focusOnTocButton();
const elementThatIsFocused = document.activeElement;
expect(elementThatIsFocused.getAttribute('data-test')).toEqual('toc button');
expect(elementThatIsFocused).toHaveAttribute('data-test', 'toc button');
});
it('should allow parent to focus on settings button', () => {
const wrapper = createWrapper();
wrapper.vm.focusOnSettingsButton();
const elementThatIsFocused = document.activeElement;
expect(elementThatIsFocused.getAttribute('data-test')).toEqual('settings button');
expect(elementThatIsFocused).toHaveAttribute('data-test', 'settings button');
});
it('should allow parent to focus on search button', () => {
const wrapper = createWrapper();
wrapper.vm.focusOnSearchButton();
const elementThatIsFocused = document.activeElement;
expect(elementThatIsFocused.getAttribute('data-test')).toEqual('search button');
expect(elementThatIsFocused).toHaveAttribute('data-test', 'search button');
});

it('should emit and event when the table of contents button is clicked', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ describe('FacilityPermissionsForm', () => {
expect(wrapper.vm.selected).toEqual('nonformal');
expect(els.nonFormalRadioButton().vm.isChecked).toEqual(true);
const elementThatIsFocused = document.activeElement;
expect(elementThatIsFocused.classList.contains('ui-textbox-input')).toBe(true);
expect(elementThatIsFocused).toHaveClass('ui-textbox-input');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ describe('multiFacility signUpPage component', () => {
it('right facility', async () => {
const wrapper = makeWrapper();
const facilityLabel = wrapper.find('[data-test="facilityLabel"]').element;
expect(facilityLabel.textContent).toMatch(/Facility 1/);
expect(facilityLabel).toHaveTextContent(/Facility 1/);
await wrapper.vm.$store.commit('SET_FACILITY_ID', 2);
expect(facilityLabel.textContent).toMatch(/Facility 2/);
expect(facilityLabel).toHaveTextContent(/Facility 2/);
});
});
16 changes: 10 additions & 6 deletions packages/kolibri-tools/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ module.exports = {
'plugin:vue/recommended',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:jest-dom/recommended',
'prettier',
],
plugins: ['import', 'vue', 'kolibri'],
plugins: ['import', 'vue', 'kolibri', 'jest-dom'],
settings: {
'import/resolver': {
[path.resolve(path.join(path.dirname(__filename), './lib/alias_import_resolver.js'))]: {
Expand All @@ -68,7 +69,7 @@ module.exports = {
},
rules: {
'comma-style': ERROR,
"no-console": ERROR,
'no-console': ERROR,
'max-len': [
ERROR,
100,
Expand Down Expand Up @@ -221,9 +222,12 @@ module.exports = {
'kolibri/vue-no-undefined-string-uses': ERROR,
'kolibri/vue-string-objects-formatting': ERROR,

'prefer-const': [ERROR, {
destructuring: 'any',
ignoreReadBeforeAssign: false
}]
'prefer-const': [
ERROR,
{
destructuring: 'any',
ignoreReadBeforeAssign: false,
},
],
},
};
10 changes: 5 additions & 5 deletions packages/kolibri-tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"@babel/plugin-syntax-import-assertions": "^7.22.5",
"@babel/plugin-transform-runtime": "^7.23.9",
"@babel/preset-env": "^7.23.9",
"@testing-library/jest-dom": "^6.1.6",
"@vue/test-utils": "^1.3.6",
"ast-traverse": "^0.1.1",
"autoprefixer": "10.4.16",
Expand All @@ -44,6 +43,7 @@
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jest": "^23.3.0",
"eslint-plugin-kolibri": "0.16.0-dev.7",
"eslint-plugin-jest-dom": "^5.1.0",
"eslint-plugin-vue": "^7.3.0",
"espree": "9.6.1",
"esquery": "^1.5.0",
Expand Down Expand Up @@ -81,6 +81,7 @@
"stylelint-config-standard": "24.0.0",
"stylelint-csstree-validator": "3.0.0",
"stylelint-scss": "5.3.2",
"rewire": "^6.0.0",
"temp": "^0.8.3",
"terser-webpack-plugin": "^5.3.10",
"toml": "^3.0.0",
Expand All @@ -92,13 +93,12 @@
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"webpack-merge": "^5.10.0"
"webpack-merge": "^5.10.0",
"@testing-library/jest-dom": "^6.4.1",
"@testing-library/vue": "^5"
},
"engines": {
"node": "18.x",
"npm": ">= 8"
},
"devDependencies": {
"rewire": "^6.0.0"
}
}
Loading

0 comments on commit 0a25fd5

Please sign in to comment.