chore: fix circleci on vite build (#10214)

- Switch to pnpm based build
- Switch circleci from docker to machine to have more memory
- Fix frontend and backend tests

Fixes
https://linear.app/chatwoot/issue/CW-3610/fix-circle-ci-for-vite-build
---------

Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
Co-authored-by: Pranav <pranavrajs@gmail.com>
Co-authored-by: Pranav <pranav@chatwoot.com>
This commit is contained in:
Vishnu Narayanan
2024-10-07 15:27:41 +05:30
committed by GitHub
parent 0677d8763d
commit ee02923ace
54 changed files with 1130 additions and 1334 deletions

View File

@@ -1,16 +1,15 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { shallowMount } from '@vue/test-utils';
import { createStore } from 'vuex';
import { createRouter, createWebHistory } from 'vue-router';
import portalMixin from '../portalMixin';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
const localVue = createLocalVue();
localVue.use(Vuex);
localVue.use(VueRouter);
import ListAllArticles from '../../pages/portals/ListAllPortals.vue';
const router = new VueRouter({
// Create router instance
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: ':portalSlug/:locale/articles',
path: '/:portalSlug/:locale/articles', // Add leading "/"
name: 'list_all_locale_articles',
component: ListAllArticles,
},
@@ -30,18 +29,21 @@ describe('portalMixin', () => {
render() {},
title: 'TestComponent',
mixins: [portalMixin],
router,
};
store = new Vuex.Store({ getters });
wrapper = shallowMount(Component, { store, localVue });
store = createStore({ getters });
wrapper = shallowMount(Component, {
global: {
plugins: [store, router],
},
});
});
it('return account id', () => {
it('returns account id', () => {
expect(wrapper.vm.accountId).toBe(1);
});
it('returns article url', () => {
router.push({
it('returns article url', async () => {
await router.push({
name: 'list_all_locale_articles',
params: { portalSlug: 'fur-rent', locale: 'en' },
});
@@ -50,24 +52,24 @@ describe('portalMixin', () => {
);
});
it('returns portal locale', () => {
router.push({
it('returns portal locale', async () => {
await router.push({
name: 'list_all_locale_articles',
params: { portalSlug: 'fur-rent', locale: 'es' },
});
expect(wrapper.vm.portalSlug).toBe('fur-rent');
});
it('returns portal slug', () => {
router.push({
it('returns portal slug', async () => {
await router.push({
name: 'list_all_locale_articles',
params: { portalSlug: 'campaign', locale: 'es' },
});
expect(wrapper.vm.portalSlug).toBe('campaign');
});
it('returns locale name', () => {
router.push({
it('returns locale name', async () => {
await router.push({
name: 'list_all_locale_articles',
params: { portalSlug: 'fur-rent', locale: 'es' },
});

View File

@@ -128,6 +128,7 @@ export default {
<template>
<transition name="popover-animation">
<!-- eslint-disable-next-line vue/require-toggle-inside-transition -->
<div
class="min-w-[15rem] max-w-[22.5rem] p-6 overflow-y-auto border-l rtl:border-r rtl:border-l-0 border-solid border-slate-50 dark:border-slate-700"
>

View File

@@ -19,11 +19,9 @@ defineProps({
});
</script>
<!-- eslint-disable vue/no-unused-refs -->
<!-- Added ref for writing specs -->
<template>
<div
ref="reportMetricContainer"
data-test-id="reportMetricContainer"
class="p-4 m-0"
:class="{
'grayscale pointer-events-none opacity-30': disabled,
@@ -32,17 +30,17 @@ defineProps({
<h3
class="flex items-center m-0 text-sm font-medium text-slate-800 dark:text-slate-100"
>
<span ref="reportMetricLabel">{{ label }}</span>
<span data-test-id="reportMetricLabel">{{ label }}</span>
<fluent-icon
ref="reportMetricInfo"
v-tooltip="infoText"
data-test-id="reportMetricInfo"
size="14"
icon="info"
class="text-slate-500 dark:text-slate-200 my-0 mx-1 mt-0.5"
/>
</h3>
<h4
ref="reportMetricValue"
data-test-id="reportMetricValue"
class="mt-1 mb-0 text-3xl font-thin text-slate-700 dark:text-slate-100"
>
{{ value }}

View File

@@ -1,17 +1,7 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { shallowMount } from '@vue/test-utils';
import { createStore } from 'vuex';
import CsatMetrics from '../CsatMetrics.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
const mountParams = {
mocks: {
$t: msg => msg,
},
stubs: ['csat-metric-card', 'woot-horizontal-bar'],
};
describe('CsatMetrics.vue', () => {
let getters;
let store;
@@ -21,20 +11,33 @@ describe('CsatMetrics.vue', () => {
beforeEach(() => {
getters = {
'csat/getMetrics': () => ({ totalResponseCount: 100 }),
'csat/getRatingPercentage': () => ({ 1: 10, 2: 20, 3: 30, 4: 30, 5: 10 }),
'csat/getRatingPercentage': () => ({
1: 10,
2: 20,
3: 30,
4: 30,
5: 10,
}),
'csat/getSatisfactionScore': () => 85,
'csat/getResponseRate': () => 90,
};
store = new Vuex.Store({
store = createStore({
getters,
});
wrapper = shallowMount(CsatMetrics, {
store,
localVue,
propsData: { filters },
...mountParams,
global: {
plugins: [store], // Ensure the store is injected here
mocks: {
$t: msg => msg, // mock translation function
},
stubs: {
CsatMetricCard: '<csat-metric-card/>',
BarChart: '<woot-horizontal-bar/>',
},
},
props: { filters },
});
});
@@ -54,13 +57,11 @@ describe('CsatMetrics.vue', () => {
});
it('hides report card if rating filter is enabled', () => {
expect(wrapper.find({ ref: 'csatHorizontalBarChart' }).exists()).toBe(
false
);
expect(wrapper.html()).not.toContain('bar-chart-stub');
});
it('shows report card if rating filter is not enabled', async () => {
await wrapper.setProps({ filters: {} });
expect(wrapper.find({ ref: 'csatHorizontalBarChart' }).exists()).toBe(true);
expect(wrapper.html()).toContain('bar-chart-stub');
});
});

View File

@@ -1,11 +1,8 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { shallowMount } from '@vue/test-utils';
import { createStore } from 'vuex';
import ReportsFiltersAgents from '../../Filters/Agents.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
const mockStore = new Vuex.Store({
const mockStore = createStore({
modules: {
agents: {
namespaced: true,
@@ -23,25 +20,26 @@ const mockStore = new Vuex.Store({
});
const mountParams = {
localVue,
store: mockStore,
mocks: {
$t: msg => msg,
global: {
plugins: [mockStore],
mocks: {
$t: msg => msg,
},
stubs: ['multiselect'],
},
stubs: ['multiselect'],
};
describe('ReportsFiltersAgents.vue', () => {
it('emits "agents-filter-selection" event when handleInput is called', () => {
it('emits "agents-filter-selection" event when handleInput is called', async () => {
const wrapper = shallowMount(ReportsFiltersAgents, mountParams);
const selectedAgents = [
{ id: 1, name: 'Agent 1' },
{ id: 2, name: 'Agent 2' },
];
wrapper.setData({ selectedOptions: selectedAgents });
await wrapper.setData({ selectedOptions: selectedAgents });
wrapper.vm.handleInput();
await wrapper.vm.handleInput();
expect(wrapper.emitted('agentsFilterSelection')).toBeTruthy();
expect(wrapper.emitted('agentsFilterSelection')[0]).toEqual([

View File

@@ -3,10 +3,12 @@ import ReportsFiltersDateGroupBy from '../../Filters/DateGroupBy.vue';
import { GROUP_BY_OPTIONS } from '../../../constants';
const mountParams = {
mocks: {
$t: msg => msg,
global: {
mocks: {
$t: msg => msg,
},
stubs: ['multiselect'],
},
stubs: ['multiselect'],
};
describe('ReportsFiltersDateGroupBy.vue', () => {

View File

@@ -3,10 +3,12 @@ import ReportFiltersDateRange from '../../Filters/DateRange.vue';
import { DATE_RANGE_OPTIONS } from '../../../constants';
const mountParams = {
mocks: {
$t: msg => msg,
global: {
mocks: {
$t: msg => msg,
},
stubs: ['multiselect'],
},
stubs: ['multiselect'],
};
describe('ReportFiltersDateRange.vue', () => {

View File

@@ -1,15 +1,14 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { shallowMount } from '@vue/test-utils';
import { createStore } from 'vuex';
import ReportsFiltersInboxes from '../../Filters/Inboxes.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
const mountParams = {
mocks: {
$t: msg => msg,
global: {
mocks: {
$t: msg => msg,
},
stubs: ['multiselect'],
},
stubs: ['multiselect'],
};
describe('ReportsFiltersInboxes.vue', () => {
@@ -30,7 +29,7 @@ describe('ReportsFiltersInboxes.vue', () => {
},
};
store = new Vuex.Store({
store = createStore({
modules: {
inboxes: inboxesModule,
},
@@ -39,24 +38,26 @@ describe('ReportsFiltersInboxes.vue', () => {
it('dispatches "inboxes/get" action when component is mounted', () => {
shallowMount(ReportsFiltersInboxes, {
store,
localVue,
...mountParams,
global: {
plugins: [store],
...mountParams.global,
},
});
expect(inboxesModule.actions.get).toHaveBeenCalled();
});
it('emits "inbox-filter-selection" event when handleInput is called', () => {
it('emits "inbox-filter-selection" event when handleInput is called', async () => {
const wrapper = shallowMount(ReportsFiltersInboxes, {
store,
localVue,
...mountParams,
global: {
plugins: [store],
...mountParams.global,
},
});
const selectedInbox = { id: 1, name: 'Inbox 1' };
wrapper.setData({ selectedOption: selectedInbox });
await wrapper.setData({ selectedOption: selectedInbox });
wrapper.vm.handleInput();
await wrapper.vm.handleInput();
expect(wrapper.emitted('inboxFilterSelection')).toBeTruthy();
expect(wrapper.emitted('inboxFilterSelection')[0]).toEqual([selectedInbox]);

View File

@@ -1,15 +1,14 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { shallowMount } from '@vue/test-utils';
import { createStore } from 'vuex';
import ReportsFiltersLabels from '../../Filters/Labels.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
const mountParams = {
mocks: {
$t: msg => msg,
global: {
mocks: {
$t: msg => msg,
},
stubs: ['multiselect'],
},
stubs: ['multiselect'],
};
describe('ReportsFiltersLabels.vue', () => {
@@ -30,7 +29,7 @@ describe('ReportsFiltersLabels.vue', () => {
},
};
store = new Vuex.Store({
store = createStore({
modules: {
labels: labelsModule,
},
@@ -39,24 +38,26 @@ describe('ReportsFiltersLabels.vue', () => {
it('dispatches "labels/get" action when component is mounted', () => {
shallowMount(ReportsFiltersLabels, {
store,
localVue,
...mountParams,
global: {
plugins: [store],
...mountParams.global,
},
});
expect(labelsModule.actions.get).toHaveBeenCalled();
});
it('emits "labels-filter-selection" event when handleInput is called', () => {
it('emits "labels-filter-selection" event when handleInput is called', async () => {
const wrapper = shallowMount(ReportsFiltersLabels, {
store,
localVue,
...mountParams,
global: {
plugins: [store],
...mountParams.global,
},
});
const selectedLabel = { id: 1, title: 'Label 1', color: 'red' };
wrapper.setData({ selectedOption: selectedLabel });
await wrapper.setData({ selectedOption: selectedLabel });
wrapper.vm.handleInput();
await wrapper.vm.handleInput();
expect(wrapper.emitted('labelsFilterSelection')).toBeTruthy();
expect(wrapper.emitted('labelsFilterSelection')[0]).toEqual([

View File

@@ -1,27 +1,26 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { shallowMount } from '@vue/test-utils';
import ReportFiltersRatings from '../../Filters/Ratings.vue';
import { CSAT_RATINGS } from 'shared/constants/messages';
const mountParams = {
mocks: {
$t: msg => msg,
global: {
mocks: {
$t: msg => msg,
},
stubs: ['multiselect'],
},
stubs: ['multiselect'],
};
const localVue = createLocalVue();
describe('ReportFiltersRatings.vue', () => {
it('emits "rating-filter-selection" event when handleInput is called', () => {
it('emits "rating-filter-selection" event when handleInput is called', async () => {
const wrapper = shallowMount(ReportFiltersRatings, {
localVue,
...mountParams,
});
const selectedRating = { value: 1, label: 'Rating 1' };
wrapper.setData({ selectedOption: selectedRating });
await wrapper.setData({ selectedOption: selectedRating });
wrapper.vm.handleInput(selectedRating);
await wrapper.vm.handleInput(selectedRating);
expect(wrapper.emitted('ratingFilterSelection')).toBeTruthy();
expect(wrapper.emitted('ratingFilterSelection')[0]).toEqual([
@@ -31,7 +30,6 @@ describe('ReportFiltersRatings.vue', () => {
it('initializes options correctly', () => {
const wrapper = shallowMount(ReportFiltersRatings, {
localVue,
...mountParams,
});

View File

@@ -1,15 +1,14 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { shallowMount } from '@vue/test-utils';
import { createStore } from 'vuex';
import ReportsFiltersTeams from '../../Filters/Teams.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
const mountParams = {
mocks: {
$t: msg => msg,
global: {
mocks: {
$t: msg => msg,
},
stubs: ['multiselect'],
},
stubs: ['multiselect'],
};
describe('ReportsFiltersTeams.vue', () => {
@@ -30,7 +29,7 @@ describe('ReportsFiltersTeams.vue', () => {
},
};
store = new Vuex.Store({
store = createStore({
modules: {
teams: teamsModule,
},
@@ -39,21 +38,25 @@ describe('ReportsFiltersTeams.vue', () => {
it('dispatches "teams/get" action when component is mounted', () => {
shallowMount(ReportsFiltersTeams, {
store,
localVue,
...mountParams,
global: {
plugins: [store],
...mountParams,
},
});
expect(teamsModule.actions.get).toHaveBeenCalled();
});
it('emits "team-filter-selection" event when handleInput is called', () => {
it('emits "team-filter-selection" event when handleInput is called', async () => {
const wrapper = shallowMount(ReportsFiltersTeams, {
store,
localVue,
...mountParams,
global: {
plugins: [store],
...mountParams,
},
});
wrapper.setData({ selectedOption: { id: 1, name: 'Team 1' } });
wrapper.vm.handleInput();
await wrapper.setData({ selectedOption: { id: 1, name: 'Team 1' } });
await wrapper.vm.handleInput();
expect(wrapper.emitted('teamFilterSelection')).toBeTruthy();
expect(wrapper.emitted('teamFilterSelection')[0]).toEqual([
{ id: 1, name: 'Team 1' },

View File

@@ -1,34 +1,36 @@
import { createLocalVue, shallowMount } from '@vue/test-utils';
import { shallowMount } from '@vue/test-utils';
import ReportMetricCard from '../ReportMetricCard.vue';
import FloatingVue from 'floating-vue';
const localVue = createLocalVue();
localVue.use(FloatingVue);
describe('ReportMetricCard.vue', () => {
const globalConfig = {
global: {
stubs: {
'fluent-icon': true, // Replace FluentIcon with a stub
},
},
};
it('renders props correctly', () => {
const label = 'Total Responses';
const value = '100';
const infoText = 'Total number of responses';
const wrapper = shallowMount(ReportMetricCard, {
propsData: { label, value, infoText },
localVue,
stubs: ['fluent-icon'],
props: { label, value, infoText },
...globalConfig,
});
expect(wrapper.find({ ref: 'reportMetricLabel' }).text()).toMatch(label);
expect(wrapper.find({ ref: 'reportMetricValue' }).text()).toMatch(value);
expect(wrapper.find({ ref: 'reportMetricInfo' }).classes()).toContain(
'has-tooltip'
expect(wrapper.find('[data-test-id="reportMetricLabel"]').text()).toMatch(
label
);
expect(wrapper.find('[data-test-id="reportMetricValue"]').text()).toMatch(
value
);
});
it('adds disabled class when disabled prop is true', () => {
const wrapper = shallowMount(ReportMetricCard, {
propsData: { label: '', value: '', infoText: '', disabled: true },
localVue,
stubs: ['fluent-icon'],
props: { label: '', value: '', infoText: '', disabled: true },
...globalConfig,
});
expect(wrapper.classes().join(' ')).toContain(
@@ -38,13 +40,12 @@ describe('ReportMetricCard.vue', () => {
it('does not add disabled class when disabled prop is false', () => {
const wrapper = shallowMount(ReportMetricCard, {
propsData: { label: '', value: '', infoText: '', disabled: false },
localVue,
stubs: ['fluent-icon'],
props: { label: '', value: '', infoText: '', disabled: false },
...globalConfig,
});
expect(
wrapper.find({ ref: 'reportMetricContainer' }).classes().join(' ')
wrapper.find('[data-test-id="reportMetricContainer"]').classes().join(' ')
).not.toContain('grayscale pointer-events-none opacity-30');
});
});

View File

@@ -2,9 +2,9 @@
exports[`CsatMetrics.vue > computes response count correctly 1`] = `
"<div class="flex-col lg:flex-row flex flex-wrap mx-0 bg-white dark:bg-slate-800 rounded-[4px] p-4 mb-5 border border-solid border-slate-75 dark:border-slate-700">
<csatmetriccard-stub label="CSAT_REPORTS.METRIC.TOTAL_RESPONSES.LABEL" value="100" infotext="CSAT_REPORTS.METRIC.TOTAL_RESPONSES.TOOLTIP" class="xs:w-full sm:max-w-[50%] lg:w-1/6 lg:max-w-[16%]"></csatmetriccard-stub>
<csatmetriccard-stub label="CSAT_REPORTS.METRIC.SATISFACTION_SCORE.LABEL" value="--" infotext="CSAT_REPORTS.METRIC.SATISFACTION_SCORE.TOOLTIP" disabled="true" class="xs:w-full sm:max-w-[50%] lg:w-1/6 lg:max-w-[16%]"></csatmetriccard-stub>
<csatmetriccard-stub label="CSAT_REPORTS.METRIC.RESPONSE_RATE.LABEL" value="90%" infotext="CSAT_REPORTS.METRIC.RESPONSE_RATE.TOOLTIP" class="xs:w-full sm:max-w-[50%] lg:w-1/6 lg:max-w-[16%]"></csatmetriccard-stub>
<!---->
<csat-metric-card-stub label="CSAT_REPORTS.METRIC.TOTAL_RESPONSES.LABEL" infotext="CSAT_REPORTS.METRIC.TOTAL_RESPONSES.TOOLTIP" disabled="false" class="xs:w-full sm:max-w-[50%] lg:w-1/6 lg:max-w-[16%]" value="100"></csat-metric-card-stub>
<csat-metric-card-stub label="CSAT_REPORTS.METRIC.SATISFACTION_SCORE.LABEL" infotext="CSAT_REPORTS.METRIC.SATISFACTION_SCORE.TOOLTIP" disabled="true" class="xs:w-full sm:max-w-[50%] lg:w-1/6 lg:max-w-[16%]" value="--"></csat-metric-card-stub>
<csat-metric-card-stub label="CSAT_REPORTS.METRIC.RESPONSE_RATE.LABEL" infotext="CSAT_REPORTS.METRIC.RESPONSE_RATE.TOOLTIP" disabled="false" class="xs:w-full sm:max-w-[50%] lg:w-1/6 lg:max-w-[16%]" value="90%"></csat-metric-card-stub>
<!--v-if-->
</div>"
`;

View File

@@ -2,7 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router';
import { frontendURL } from '../helper/URLHelper';
import dashboard from './dashboard/dashboard.routes';
import store from '../store';
import store from 'dashboard/store';
import { validateLoggedInRoutes } from '../helper/routeHelpers';
import AnalyticsHelper from '../helper/AnalyticsHelper';
import { buildPermissionsFromRouter } from '../helper/permissionsHelper';
@@ -16,8 +16,8 @@ export const validateAuthenticateRoutePermission = (to, next) => {
const { isLoggedIn, getCurrentUser: user } = store.getters;
if (!isLoggedIn) {
window.location = '/app/login';
return '/app/login';
window.location.assign('/app/login');
return '';
}
if (!to.name) {

View File

@@ -1,79 +1,105 @@
import { validateAuthenticateRoutePermission } from './index';
import store from '../store'; // This import will be mocked
import { vi } from 'vitest';
// Mock the store module
vi.mock('../store', () => ({
default: {
getters: {
isLoggedIn: false,
getCurrentUser: {
account_id: null,
id: null,
accounts: [],
},
},
},
}));
describe('#validateAuthenticateRoutePermission', () => {
describe(`when route is protected`, () => {
describe(`when user not logged in`, () => {
it(`should redirect to login`, () => {
const to = { name: 'some-protected-route', params: { accountId: 1 } };
const next = vi.fn();
const getters = {
isLoggedIn: false,
getCurrentUser: {
account_id: null,
id: null,
accounts: [],
let next;
beforeEach(() => {
next = vi.fn(); // Mock the next function
});
describe('when user is not logged in', () => {
it('should redirect to login', () => {
const to = { name: 'some-protected-route', params: { accountId: 1 } };
// Mock the store to simulate user not logged in
store.getters.isLoggedIn = false;
// Mock window.location.assign
const mockAssign = vi.fn();
delete window.location;
window.location = { assign: mockAssign };
validateAuthenticateRoutePermission(to, next);
expect(mockAssign).toHaveBeenCalledWith('/app/login');
});
});
describe('when user is logged in', () => {
beforeEach(() => {
// Mock the store's getter for a logged-in user
store.getters.isLoggedIn = true;
store.getters.getCurrentUser = {
account_id: 1,
id: 1,
accounts: [
{
id: 1,
role: 'agent',
permissions: ['agent'],
status: 'active',
},
],
};
});
describe('when route is not accessible to current user', () => {
it('should redirect to dashboard', () => {
const to = {
name: 'general_settings_index',
params: { accountId: 1 },
meta: { permissions: ['administrator'] },
};
expect(validateAuthenticateRoutePermission(to, next, { getters })).toBe(
'/app/login'
);
validateAuthenticateRoutePermission(to, next);
expect(next).toHaveBeenCalledWith('/app/accounts/1/dashboard');
});
});
describe(`when user is logged in`, () => {
describe(`when route is not accessible to current user`, () => {
it(`should redirect to dashboard`, () => {
const to = {
name: 'general_settings_index',
params: { accountId: 1 },
meta: { permissions: ['administrator'] },
};
const next = vi.fn();
const getters = {
isLoggedIn: true,
getCurrentUser: {
account_id: 1,
describe('when route is accessible to current user', () => {
beforeEach(() => {
// Adjust store getters to reflect the user has admin permissions
store.getters.getCurrentUser = {
account_id: 1,
id: 1,
accounts: [
{
id: 1,
accounts: [
{
permissions: ['agent'],
id: 1,
role: 'agent',
status: 'active',
},
],
role: 'administrator',
permissions: ['administrator'],
status: 'active',
},
};
validateAuthenticateRoutePermission(to, next, { getters });
expect(next).toHaveBeenCalledWith('/app/accounts/1/dashboard');
});
],
};
});
describe(`when route is accessible to current user`, () => {
it(`should go there`, () => {
const to = {
name: 'general_settings_index',
params: { accountId: 1 },
meta: { permissions: ['administrator'] },
};
const next = vi.fn();
const getters = {
isLoggedIn: true,
getCurrentUser: {
account_id: 1,
id: 1,
accounts: [
{
id: 1,
role: 'administrator',
permissions: ['administrator'],
status: 'active',
},
],
},
};
validateAuthenticateRoutePermission(to, next, { getters });
expect(next).toHaveBeenCalledWith();
});
it('should go to the intended route', () => {
const to = {
name: 'general_settings_index',
params: { accountId: 1 },
meta: { permissions: ['administrator'] },
};
validateAuthenticateRoutePermission(to, next);
expect(next).toHaveBeenCalledWith();
});
});
});