lint + correcting some actions

This commit is contained in:
Frank 2021-11-17 15:56:06 -05:00
parent 8e0f9bf816
commit a500ad19e9
37 changed files with 488 additions and 464 deletions

View file

@ -1,14 +1,20 @@
module.exports = {
verbose: true,
coverageReporters: ['html', 'text', 'jest-junit'],
coverageReporters: ["html", "text", "jest-junit"],
preset: "@vue/cli-plugin-unit-jest",
transform: { "^.+\\.vue$": "vue-jest", },
moduleFileExtensions: ['js', 'vue'],
collectCoverageFrom: ["src/**/*.{js,vue}", "!src/main.js", "!src/constants/*.js", "!src/router/**/*.js", "!src/helpers/*.js"], //! means exclude from coverage.
transform: { "^.+\\.vue$": "vue-jest" },
moduleFileExtensions: ["js", "vue"],
collectCoverageFrom: [
"src/**/*.{js,vue}",
"!src/main.js",
"!src/constants/*.js",
"!src/router/**/*.js",
"!src/helpers/*.js",
], //! means exclude from coverage.
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
coverageThreshold: {
global: {
statements: 90,
}
},
},
};

View file

@ -1,4 +1,3 @@
<template>
<router-view></router-view>
</template>

View file

@ -1,22 +1,26 @@
import { shallowMount } from '@vue/test-utils';
import radioQuestion from './radioQuestion';
import { shallowMount } from "@vue/test-utils";
import radioQuestion from "./radioQuestion";
describe('radioQuestion.vue', () => {
it("Should render the 'questionText' prop value as a span value for the radio question and the 'answer' values should render as text values for radio components.", () => {
// Act
const wrapper = shallowMount(radioQuestion, {
propsData: {
questionText: 'Question Text',
answers: ['2023', '2022', '2021'],
chooseAnswer: function(test){ console.log(test) }
}
});
describe("radioQuestion.vue", () => {
it("Should render the 'questionText' prop value as a span value for the radio question and the 'answer' values should render as text values for radio components.", () => {
// Act
const wrapper = shallowMount(radioQuestion, {
propsData: {
questionText: "Question Text",
answers: ["2023", "2022", "2021"],
chooseAnswer: function (test) {
console.log(test);
},
},
});
// Assert
expect(wrapper.find('.needed_car_info-text').text()).toEqual('Question Text');
const radioButtons = wrapper.findAllComponents('[data-test="radio"]');
expect(radioButtons[0].attributes('text')).toEqual('2023');
expect(radioButtons[2].attributes('text')).toEqual('2021');
expect(typeof wrapper.props().chooseAnswer).toBe('function');
})
})
// Assert
expect(wrapper.find(".needed_car_info-text").text()).toEqual(
"Question Text"
);
const radioButtons = wrapper.findAllComponents('[data-test="radio"]');
expect(radioButtons[0].attributes("text")).toEqual("2023");
expect(radioButtons[2].attributes("text")).toEqual("2021");
expect(typeof wrapper.props().chooseAnswer).toBe("function");
});
});

View file

@ -1,13 +1,20 @@
<template>
<div class="radio_question">
<div class="needed_car_info d-flex mt-4 mb-3">
<span class="text-center fs-6 fw-bold w-100 needed_car_info-text">{{ questionText }}</span>
<span class="text-center fs-6 fw-bold w-100 needed_car_info-text">{{
questionText
}}</span>
</div>
<div class="car_list overflow-scroll position-absolute">
<div v-for="answer in answers" :key="answer" class="mb-2">
<radio :text="answer" :value="answer" @click="chooseAnswer(answer)" data-test="radio" />
</div>
<div class="car_list overflow-scroll position-absolute">
<div v-for="answer in answers" :key="answer" class="mb-2">
<radio
:text="answer"
:value="answer"
@click="chooseAnswer(answer)"
data-test="radio"
/>
</div>
</div>
</div>
</template>
@ -18,10 +25,10 @@ export default {
props: {
questionText: String,
answers: Array,
chooseAnswer: Function
chooseAnswer: Function,
},
components: {
radio
}
radio,
},
};
</script>

View file

@ -1,5 +1,5 @@
const applicationConfig = {
CONSUMER_APIGATEWAY_URL: process.env.VUE_APP_CONSUMER_API_GATEWAY
}
CONSUMER_APIGATEWAY_URL: process.env.VUE_APP_CONSUMER_API_GATEWAY,
};
export { applicationConfig }
export { applicationConfig };

View file

@ -1,28 +1,28 @@
const endpoints = {
GetRouteInfoEndpoint: {
url: '/content/api/v1/content/RouteInfo',
method: 'POST'
},
GetYears: {
url: '/vehicle/api/v1/vehicle/years',
method: 'GET'
},
GetMakes: {
url: '/vehicle/api/v1/vehicle/Makes',
method: 'POST'
},
GetVehicleModels: {
url: '/vehicle/api/v1/vehicle/Models',
method: 'GET'
},
GetStyles: {
url: '/vehicle/api/v1/vehicle/Styles',
method: 'POST'
},
GetPageData: {
url: '/content/api/v1/content/{pageName}',
method: 'GET'
}
}
GetRouteInfo: {
url: "/content/api/v1/content/RouteInfo",
method: "POST",
},
GetVehicleYears: {
url: "/vehicle/api/v1/vehicle/years",
method: "GET",
},
GetVehicleMakes: {
url: "/vehicle/api/v1/vehicle/Makes",
method: "GET",
},
GetVehicleModels: {
url: "/vehicle/api/v1/vehicle/Models",
method: "GET",
},
GetVehicleStyles: {
url: "/vehicle/api/v1/vehicle/Styles",
method: "GET",
},
GetPageData: {
url: "/content/api/v1/content",
method: "GET",
},
};
export { endpoints }
export { endpoints };

View file

@ -1,8 +1,10 @@
const storeActions = {
GET_ROUTE_INFO_ACTION: "getRouteInfo",
GET_YEARS: 'getYears',
GET_VEHICLE_MODELS: 'getVehicleModels',
GET_PAGE_DATA: 'getPageData',
}
GET_ROUTE_INFO_ACTION: "getRouteInfo",
GET_PAGE_DATA: "getPageData",
GET_VEHICLE_YEARS: "getVehicleYears",
GET_VEHICLE_MAKES: "getVehicleMakes",
GET_VEHICLE_MODELS: "getVehicleModels",
GET_VEHICLE_STYLES: "getVehicleStyles",
};
export { storeActions }
export { storeActions };

View file

@ -1,7 +1,6 @@
const widgetNames = {
HEADER_TEXT_WIDGET: "HeaderTextWidget",
RADIO_QUESTION_WIDGET: "RadioQuestionWidget"
}
HEADER_TEXT_WIDGET: "HeaderTextWidget",
RADIO_QUESTION_WIDGET: "RadioQuestionWidget",
};
export { widgetNames }
export { widgetNames };

View file

@ -3,11 +3,12 @@ import { applicationConfig } from "@/constants/applicationConfig.js";
import httpStatusCodes from "http-status-codes";
export default {
callHttpClient({ method, endpoint, payload}) {
callHttpClient({ method, endpoint, payload }) {
return new Promise((resolve, reject) => {
const apiGatewayUrl = applicationConfig.CONSUMER_APIGATEWAY_URL;
const payloadAndAnalyticsData = Object.assign({}, payload, {AppName: "FixMyGlass"});
const payloadAndAnalyticsData = Object.assign({}, payload, {
AppName: "FixMyGlass",
});
axios({
method: method,
@ -15,7 +16,8 @@ export default {
data: payloadAndAnalyticsData,
crossDomain: true,
responseType: {},
}).then((response) => {
}).then(
(response) => {
if (response.status == httpStatusCodes.OK) {
resolve(response);
} else {
@ -29,19 +31,17 @@ export default {
});
},
/* istanbul ignore next */
callMockHttpClient({ method, endpoint}) {
callMockHttpClient({ method, endpoint }) {
// For Mock use only!
return new Promise((resolve, reject) => {
axios({
method: method,
url: endpoint,
crossDomain: true,
responseType: {},
}).then((response) => {
}).then(
(response) => {
if (response.status == httpStatusCodes.OK) {
resolve(response);
} else {
@ -53,5 +53,5 @@ export default {
}
);
});
}
},
};

View file

@ -1,73 +1,76 @@
import globalMethods from "@/global-methods";
import axios from 'axios';
import axios from "axios";
//Mock external dependencies
jest.mock('axios');
jest.mock("axios");
it("Global Methods - Call Http Client - Should Resolve Promise", () => {
//Arrange
const endpoint = 'https://mock.safelite.com';
const httpArgs = setupMocksForHttpClient({ endpoint: endpoint });
//Arrange
const endpoint = "https://mock.safelite.com";
const httpArgs = setupMocksForHttpClient({ endpoint: endpoint });
//Act
globalMethods.callHttpClient(httpArgs)
.then((response) => {
//Assert
expect(axios.mock.calls[0][0].url).toContain(endpoint);
expect(response.data.message).toContain('Success');
expect(response.status).toEqual(200);
});
//Act
globalMethods.callHttpClient(httpArgs).then((response) => {
//Assert
expect(axios.mock.calls[0][0].url).toContain(endpoint);
expect(response.data.message).toContain("Success");
expect(response.status).toEqual(200);
});
});
it("Global Methods - Call Http Client - Should Reject Promise", () => {
//Arrange
const endpoint = 'https://mock.safelite.com';
const httpArgs = setupMocksForHttpClient({ endpoint: endpoint, isError: true });
//Arrange
const endpoint = "https://mock.safelite.com";
const httpArgs = setupMocksForHttpClient({
endpoint: endpoint,
isError: true,
});
//Act
globalMethods.callHttpClient(httpArgs)
.catch((err) => {
//Assert
expect(axios.mock.calls[0][0].url).toContain(endpoint);
expect(err.data.message).toContain('Error');
expect(err.status).toEqual(500);
});
//Act
globalMethods.callHttpClient(httpArgs).catch((err) => {
//Assert
expect(axios.mock.calls[0][0].url).toContain(endpoint);
expect(err.data.message).toContain("Error");
expect(err.status).toEqual(500);
});
});
function setupMocksForHttpClient({ endpoint = null, isError = false, additionalData = null }) {
function setupMocksForHttpClient({
endpoint = null,
isError = false,
additionalData = null,
}) {
//Clear node module
axios.mockClear();
//Clear node module
axios.mockClear();
// Success Response
const response = {
status: 200,
data: {
message: "Success",
additionalData: additionalData,
},
};
// Success Response
const response = {
status: 200,
data: {
message: 'Success',
additionalData: additionalData
}
};
// Error Response
const error = {
response: {
status: 500,
data: {
message: "Error",
additionalData: additionalData,
},
},
};
// Error Response
const error = {
response: {
status: 500,
data: {
message: 'Error',
additionalData: additionalData
}
}
}
// Error interceptor on Axios returns a different object, so we need to mimic that.
if (isError) {
axios.mockRejectedValue(error);
} else {
axios.mockResolvedValue(response);
}
// Error interceptor on Axios returns a different object, so we need to mimic that.
if (isError) {
axios.mockRejectedValue(error);
} else {
axios.mockResolvedValue(response);
}
return {
endpoint: endpoint
}
}
return {
endpoint: endpoint,
};
}

View file

@ -1,26 +1,26 @@
import { storeActions } from "@/constants/storeActions";
export function getMountOptions(mockData) {
// Define our mocks to attached to the 'global' object for Vue/Jest.
const mocks = {};
// Define our mocks to attached to the 'global' object for Vue/Jest.
const mocks = {};
mocks.dispatchNonBlockingStoreAction = jest.fn();
mocks.dispatchNonBlockingStoreAction.mockImplementation((actionName) => {
let actionFilterResult = mockData.actionList.filter(x => x.actionName == actionName);
if (actionFilterResult.length > 0 && actionFilterResult.length === 1) {
mocks.dispatchNonBlockingStoreAction = jest.fn();
mocks.dispatchNonBlockingStoreAction.mockImplementation((actionName) => {
let actionFilterResult = mockData.actionList.filter(
(x) => x.actionName == actionName
);
return Promise.resolve({
data: actionFilterResult[0].data
});
}
});
// Mock store actions from js file
mocks.storeActions = storeActions;
const global = {
mocks: mocks
};
if (actionFilterResult.length > 0 && actionFilterResult.length === 1) {
return Promise.resolve({
data: actionFilterResult[0].data,
});
}
});
// Mock store actions from js file
mocks.storeActions = storeActions;
const global = {
mocks: mocks,
};
return { global }
}
return { global };
}

View file

@ -1,4 +1,4 @@
<template>
<template>
<div class="container-fluid container-shadow p-2 rounded-3">
<div class="row g-2">
<radioCard
@ -25,31 +25,30 @@
</div>
<div class="row">
<div class="col my-3 d-flex align-items-center">
<buttonPrimary
buttonText="Primary"
/>
<buttonPrimary buttonText="Primary" />
</div>
</div>
<div class="row">
<div class="col my-3 d-flex align-items-center">
<buttonSecondary
buttonText="Secondary"
/>
<buttonSecondary buttonText="Secondary" />
</div>
</div>
<div class="row">
<div class="col my-3 d-flex align-items-center">
<listButton
buttonText="List Button"
errorText="Test error message"
/>
<listButton buttonText="List Button" errorText="Test error message" />
</div>
</div>
<div class="row">
<!-- The role="radiogroup" and aria-labelledby must be included in the parent component for the radio group -->
<div role="radiogroup" aria-labelledby="select-year-radio-group" class="col my-3 d-flex align-items-center flex-column">
<div
role="radiogroup"
aria-labelledby="select-year-radio-group"
class="col my-3 d-flex align-items-center flex-column"
>
<!-- The h3 and id must be included. The id must match the aria-labelledby of the parent div. -->
<h3 class="visually-hidden" id="select-year-radio-group">Select Vehicle Year</h3>
<h3 class="visually-hidden" id="select-year-radio-group">
Select Vehicle Year
</h3>
<radioList
groupName="demo"
ariaLabelBy="vehicle-year"
@ -78,8 +77,12 @@
<div class="row my-2">
<div class="col">
<p>This is default body copy font size/weight</p>
<p class="small">This is small body copy using <code>.small</code> class</p>
<p><small>This is also small using <code>&lt;small&gt;</code> tag</small></p>
<p class="small">
This is small body copy using <code>.small</code> class
</p>
<p>
<small>This is also small using <code>&lt;small&gt;</code> tag</small>
</p>
</div>
</div>
<div class="row my-2">
@ -138,12 +141,12 @@ export default {
buttonSecondary,
radioCard,
listButton,
radioList
radioList,
},
data() {
return {
years: [2023, 2022, 2021, 2020],
};
}
},
};
</script>

View file

@ -1,3 +1,3 @@
<template>
<p> Not Found .... :( </p>
</template>
<p>Not Found .... :(</p>
</template>

View file

@ -1,55 +1,52 @@
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue'
import { getMountOptions } from '@/helpers/unitTestHelper.js';
import { storeActions } from '@/constants/storeActions.js'
import selectYear from './selectYear.vue';
import { shallowMount } from "@vue/test-utils";
import { nextTick } from "vue";
import { getMountOptions } from "@/helpers/unitTestHelper.js";
import { storeActions } from "@/constants/storeActions.js";
import selectYear from "./selectYear.vue";
describe('selectYear.vue', () => {
test("Should render the 'pageHeader.Text' data value 'text' prop value for the Header component, 'radioQuestion.Question' data value as 'questionText' prop value for the 'radioQuestion' component and 'years' values for 'answers' prop values for the 'radioQuestion' component.", async () => {
// Arrange
const mockDataAndAction = {
actionList: [
{
actionName: storeActions.GET_PAGE_DATA,
data: {
"Result": [
{
Type: "PageHeadingWidget",
Model: {
Text: "Mock Data"
}
},
{
Type: "RadioQuestionWidget",
Model: {
Question: "Mock Data"
}
}
]
}
describe("selectYear.vue", () => {
test("Should render the 'pageHeader.Text' data value 'text' prop value for the Header component, 'radioQuestion.Question' data value as 'questionText' prop value for the 'radioQuestion' component and 'years' values for 'answers' prop values for the 'radioQuestion' component.", async () => {
// Arrange
const mockDataAndAction = {
actionList: [
{
actionName: storeActions.GET_PAGE_DATA,
data: {
Result: [
{
Type: "PageHeadingWidget",
Model: {
Text: "Mock Data",
},
{
actionName: storeActions.GET_YEARS,
data: ['2023', '2022', '2021']
}
]
};
},
{
Type: "RadioQuestionWidget",
Model: {
Question: "Mock Data",
},
},
],
},
},
{
actionName: storeActions.GET_VEHICLE_YEARS,
data: ["2023", "2022", "2021"],
},
],
};
const mountOptions = getMountOptions(mockDataAndAction);
const mountOptions = getMountOptions(mockDataAndAction);
// Act
const wrapper = shallowMount(selectYear, mountOptions);
await nextTick()
// Act
const wrapper = shallowMount(selectYear, mountOptions);
await nextTick();
// Assert
const header = await wrapper.find('.Header');
expect(header.attributes('text')).toEqual("Mock Data");
// Assert
const header = await wrapper.find(".Header");
expect(header.attributes("text")).toEqual("Mock Data");
const radioQuestion = await wrapper.findComponent('.radioQuestion');
expect(radioQuestion.attributes('answers')).toEqual('2023,2022,2021');
expect(radioQuestion.attributes('questiontext')).toEqual("Mock Data");
});
})
const radioQuestion = await wrapper.findComponent(".radioQuestion");
expect(radioQuestion.attributes("answers")).toEqual("2023,2022,2021");
expect(radioQuestion.attributes("questiontext")).toEqual("Mock Data");
});
});

View file

@ -1,8 +1,8 @@
<template>
<div class="select-car">
<div class="select-car-form rounded text-center">
<Header :text="headerTextWidgetModel.HeaderText" class="Header" />
<yearQuestion :questionText="radioQuestionWidgetModel.QuestionText" />
<!-- <Header :text="headerTextWidgetModel.HeaderText" class="Header" />
<yearQuestion :questionText="radioQuestionWidgetModel.QuestionText" /> -->
</div>
</div>
</template>
@ -10,33 +10,25 @@
<script>
import yearQuestion from "@/layouts/vehicle-year/year-question/year-question";
import Header from "@/uxComponents/header/header";
import {
mapState
} from "vuex";
export default {
name: "vehicle-year",
data() {
return {
headerTextWidgetModel: {},
radioQuestionWidgetModel: {}
headerTextWidgets: {},
radioQuestionWidgets: {},
};
},
computed: {
...mapState(["slideTransition", "carImg", "blurImg", "style"]),
},
created() {
this.dispatchNonBlockingStoreAction(this.storeActions.GET_VEHICLE_MODELS, {
year: '2020',
make: 'Alfa Romeo/Chrysler'
}, true)
.then((response) => {
console.log(response);
})
computed: {},
async mounted() {
const content = await this.GetContentFromCms();
this.headerTextWidgets = content.HeaderTextWidget;
console.log(content);
},
components: {
yearQuestion,
Header,
// yearQuestion,
// Header,
},
};
</script>

View file

@ -8,37 +8,25 @@ import store from "@/store";
import router from "@/router";
export default {
name: 'year-question',
name: "year-question",
props: {
questionText: String
questionText: String,
},
data() {
return {
years: []
}
years: [],
};
},
created() {
this.dispatchNonBlockingStoreAction(this.storeActions.GET_YEARS)
.then((response) => {
this.years = response.data;
});
mounted() {
this.dispatchNonBlockingStoreAction(this.storeActions.GET_VEHICLE_YEARS, {}
).then((response) => {
this.years = response.data;
});
},
components: {
radioQuestion
radioQuestion,
},
methods: {
selectYear(year) {
this.dispatchNonBlockingStoreAction("selectYear", {
year: year
}).then((response) => {
const makes = response;
store.commit('updateYear', {
year,
makes
});
router.push(`select-make?year=${year}`);
});
}
}
}
},
};
</script>

View file

@ -1,7 +1,7 @@
import { createApp } from "vue";
import App from "./App.vue";
import router from './router';
import store from '@/store';
import router from "./router";
import store from "@/store";
import baseMixin from "@/mixins/baseMixin.js";
//Bootstrap JavaScript
import "../node_modules/bootstrap/dist/js/bootstrap.js";

View file

@ -2,62 +2,61 @@ import { storeActions } from "@/constants/storeActions.js";
import { widgetNames } from "@/constants/widgetNames.js";
export default {
methods: {
dispatchBlockingStoreAction(type, payload) {
// globalMethods.showWaitingModal(true);
methods: {
dispatchBlockingStoreAction(type, payload) {
// globalMethods.showWaitingModal(true);
return this.dispatchNonBlockingStoreAction(type, payload)
.finally(() => {
// globalMethods.showWaitingModal(false);
});;
},
dispatchNonBlockingStoreAction(type, payload, encodePayload = false) {
return this.dispatchNonBlockingStoreAction(type, payload).finally(() => {
// globalMethods.showWaitingModal(false);
});
},
dispatchNonBlockingStoreAction(type, payload, encodePayload = false) {
// Encode the payload if required
if (encodePayload) {
encodeUriData(payload);
}
// Encode the payload if required
if (encodePayload) {
encodeUriData(payload);
return this.$store.dispatch(type, payload);
},
GetContentFromCms() {
return this.dispatchNonBlockingStoreAction(
this.storeActions.GET_PAGE_DATA,
{ pageName: this.$route.query.fmgPage }
).then((response) => {
const pageDataFromCms = {};
response.data.Result.forEach((widget) => {
if (Object.values(this.widgetNames).includes(widget.Type)) {
// If we already have this widget, push it on the collection
if (widget.Type in pageDataFromCms) {
pageDataFromCms[widget.Type].push(widget.Model);
return;
}
return this.$store.dispatch(type, payload);
},
pageDataFromCms[widget.Type] = [widget.Model];
}
});
GetContentFromCms() {
return this.dispatchNonBlockingStoreAction(this.storeActions.GET_PAGE_DATA, { pageName: this.$route.query.fmgPage })
.then((response) => {
const pageDataFromCms = {};
response.data.Result.forEach((widget) => {
if (Object.values(this.widgetNames).includes(widget.Type)) {
// If we already have this widget, push it on the collection
if (widget.Type in pageDataFromCms) {
pageDataFromCms[widget.Type].push(widget.Model);
return;
}
pageDataFromCms[widget.Type] = [widget.Model];
}
});
return pageDataFromCms;
});
}
return pageDataFromCms;
});
},
computed: {
storeActions() {
return storeActions;
},
widgetNames() {
return widgetNames;
}
},
computed: {
storeActions() {
return storeActions;
},
}
widgetNames() {
return widgetNames;
},
},
};
function encodeUriData(payload) {
if (payload && Object.keys(payload).length > 0) {
// Loop through the payload and encode the values
Object.keys(payload).forEach(key => {
payload[key] = encodeURIComponent(payload[key]);
});
}
}
if (payload && Object.keys(payload).length > 0) {
// Loop through the payload and encode the values
Object.keys(payload).forEach((key) => {
payload[key] = encodeURIComponent(payload[key]);
});
}
}

View file

@ -7,9 +7,9 @@ import store from "@/store";
const routes = [
{
path: '/:pathMatch(.*)*',
path: "/:pathMatch(.*)*",
component: NotFound,
name: "NotFound"
name: "NotFound",
},
{
path: "/component-test", // This is a temporary route for testing.
@ -19,12 +19,10 @@ const routes = [
{
path: "/",
beforeEnter(to, from, next) {
// If we have no query string, or we don't have the FmgPage query string.
if (to.query.fmgPage === undefined) {
RetainStructureAndGoTo404(to, next);
} else {
// If we already have our route, go to it.
if (router.hasRoute(to.query.fmgPage)) {
return next({
@ -34,24 +32,22 @@ const routes = [
}
// Get route info for the given url. Names will have a 1:1 relationship with names in the Cms.
GetRouteInfoFromPageName(to.query.fmgPage).then((routeData) => {
GetRouteInfoFromPageName(to.query.fmgPage)
.then((routeData) => {
// Add our dynamic route.
router.addRoute({
path: routeData[0].path, // Always the same path, because we control it with query strings.
name: routeData[0].name,
component: routeData[0].component,
});
// Add our dynamic route.
router.addRoute({
path: routeData[0].path, // Always the same path, because we control it with query strings.
name: routeData[0].name,
component: routeData[0].component,
});
// Assign current query string parameters, as well as our fmgPage one.
next({
name: routeData[0].name,
query: Object.assign(to.query, { fmgPage: routeData[0].name })
});
})
// Assign current query string parameters, as well as our fmgPage one.
next({
name: routeData[0].name,
query: Object.assign(to.query, { fmgPage: routeData[0].name }),
});
})
.catch((error) => {
// If we can't find the route, go to the 404 page.
RetainStructureAndGoTo404(to, next);
@ -68,7 +64,7 @@ const router = createRouter({
routes,
});
// Get route information by page name.
// Get route information by page name.
// This will reach out to the Cms and there is a 1:1 relationship between page names and route names.
function GetRouteInfoFromPageName(pageName) {
return new Promise((resolve, reject) => {
@ -81,14 +77,13 @@ function GetRouteInfoFromPageName(pageName) {
Object.keys(jsonFromResponse).forEach((key) => {
routeData.push({
path: '/',
path: "/",
name: `${key}`,
component: lazyLoadComponent(jsonFromResponse[key].LayoutName),
});
});
resolve(routeData);
})
.catch((error) => {
reject(error);
@ -99,10 +94,10 @@ function GetRouteInfoFromPageName(pageName) {
// Go to our 404 page but retain our structure when we go there (path, queryString, hash).
function RetainStructureAndGoTo404(to, next) {
next({
name: 'NotFound',
params: { pathMatch: to.path.split('/').slice(1) },
name: "NotFound",
params: { pathMatch: to.path.split("/").slice(1) },
query: to.query,
hash: to.hash
hash: to.hash,
});
}

View file

@ -9,23 +9,44 @@ export default createStore({
storage: window.sessionStorage,
}),
],
state: {
},
mutations: {
},
state: {},
mutations: {},
actions: {
getVehicleModels({ commit, state }, { year, make }) {
console.log(arguments);
// Vehicle API Actions
getVehicleYears(context) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleModels.method,
endpoint: `${endpoints.GetVehicleModels.url}/${year}/${encodeURI(make)}`,
payload: {}
method: endpoints.GetVehicleYears.method,
endpoint: endpoints.GetVehicleYears.url,
payload: {},
});
},
getVehicleMakes(context, { year }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleMakes.method,
endpoint: `${endpoints.GetVehicleMakes.url}/${year}`,
payload: {},
});
},
getVehicleModels(context, { year, make }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleModels.method,
endpoint: `${endpoints.GetVehicleModels.url}/${year}/${make}`,
payload: {},
});
},
getVehicleStyles(context, { year, make, model }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleStyles.method,
endpoint: `${endpoints.GetVehicleStyles.url}/${year}/${make}/${model}`,
payload: {},
});
},
// Content API Actions
getRouteInfo(context, { pageName }) {
return globalMethods.callHttpClient({
method: endpoints.GetRouteInfoEndpoint.method,
endpoint: endpoints.GetRouteInfoEndpoint.url,
method: endpoints.GetRouteInfo.method,
endpoint: endpoints.GetRouteInfo.url,
payload: {
pageName: pageName,
},
@ -34,7 +55,7 @@ export default createStore({
getPageData(context, { pageName }) {
return globalMethods.callHttpClient({
method: endpoints.GetPageData.method,
endpoint: endpoints.GetPageData.url.replace("{pageName}", pageName),
endpoint: `${endpoints.GetPageData.url}/${pageName}`,
payload: {},
});
},

View file

@ -1 +1 @@
test.todo('some test to be written in the future');
test.todo("some test to be written in the future");

View file

@ -5,7 +5,7 @@
class="btn btn-primary d-flex align-items-center"
v-on:click="showLoader()"
v-bind:class="[this.isLoading ? 'button-loader' : 'not-loading']"
>
>
{{ this.buttonText }}
</button>
</template>
@ -15,11 +15,11 @@ export default {
name: "buttonPrimary",
props: {
buttonText: String,
isDisabled: Boolean
isDisabled: Boolean,
},
data() {
return {
isLoading: false
isLoading: false,
};
},
methods: {

View file

@ -1 +1 @@
test.todo('some test to be written in the future');
test.todo("some test to be written in the future");

View file

@ -5,7 +5,7 @@
class="btn btn-secondary d-flex align-items-center"
v-on:click="showLoader()"
v-bind:class="[this.isLoading ? 'button-loader' : 'not-loading']"
>
>
{{ this.buttonText }}
</button>
</template>
@ -14,7 +14,7 @@
export default {
name: "buttonSecondary",
props: {
buttonText: String
buttonText: String,
},
data() {
return {

View file

@ -1 +1 @@
test.todo('some test to be written in the future');
test.todo("some test to be written in the future");

View file

@ -1,16 +1,16 @@
import { shallowMount } from '@vue/test-utils';
import Header from './header';
import { shallowMount } from "@vue/test-utils";
import Header from "./header";
describe('Header.vue', () => {
it("Should render the 'text' prop value as a span value for the header span text value.", () => {
// Act
const wrapper = shallowMount(Header, {
propsData: {
text: 'Header Content'
}
});
describe("Header.vue", () => {
it("Should render the 'text' prop value as a span value for the header span text value.", () => {
// Act
const wrapper = shallowMount(Header, {
propsData: {
text: "Header Content",
},
});
// Assert
expect(wrapper.find('span').text()).toContain("Header Content");
})
});
// Assert
expect(wrapper.find("span").text()).toContain("Header Content");
});
});

View file

@ -1,16 +1,16 @@
<template>
<div class="current_car_info-text">
<div class="d-flex align-items-center justify-content-center">
<span class="text-center text-dark fs-5 d-block">{{ text }}</span>
</div>
<div class="current_car_info-text">
<div class="d-flex align-items-center justify-content-center">
<span class="text-center text-dark fs-5 d-block">{{ text }}</span>
</div>
</div>
</template>
<script>
export default {
name: "Header",
props: {
text: String
}
text: String,
},
};
</script>
</script>

View file

@ -1 +1 @@
test.todo('some test to be written in the future');
test.todo("some test to be written in the future");

View file

@ -3,8 +3,11 @@
<button
class="btn list-button d-flex align-items-center"
v-on:click="showLoader()"
v-bind:class="[this.isLoading ? 'button-loader' : 'not-loading',this.isError ? 'error' : '']"
>
v-bind:class="[
this.isLoading ? 'button-loader' : 'not-loading',
this.isError ? 'error' : '',
]"
>
{{ this.buttonText }}
</button>
<label class="small mt-1">{{ this.errorText }}</label>
@ -16,12 +19,12 @@ export default {
name: "listButton",
props: {
buttonText: String,
errorText: String
errorText: String,
},
data() {
return {
isLoading: false,
isError: false
isError: false,
};
},
methods: {

View file

@ -1,23 +1,23 @@
import { shallowMount } from '@vue/test-utils';
import radio from './radio';
import { shallowMount } from "@vue/test-utils";
import radio from "./radio";
describe('radio.vue', () => {
it("Should render the 'text' prop value as a span value for the radio button label and add the 'value' prop value as the radio button value and id.", () => {
// Act
const wrapper = shallowMount(radio, {
propsData: {
value: '2023',
text: '12'
}
});
describe("radio.vue", () => {
it("Should render the 'text' prop value as a span value for the radio button label and add the 'value' prop value as the radio button value and id.", () => {
// Act
const wrapper = shallowMount(radio, {
propsData: {
value: "2023",
text: "12",
},
});
// Assert
expect(wrapper.find('span').text()).toEqual('12');
expect(wrapper.find('input').attributes()).toEqual({
class: 'position-absolute opacity-0',
id: '2023',
type: 'radio',
value: '2023'
});
})
})
// Assert
expect(wrapper.find("span").text()).toEqual("12");
expect(wrapper.find("input").attributes()).toEqual({
class: "position-absolute opacity-0",
id: "2023",
type: "radio",
value: "2023",
});
});
});

View file

@ -1,30 +1,26 @@
<template>
<div>
<div>
<input
type="radio"
:id="this.value"
:value="this.value"
class="position-absolute opacity-0"
v-on:click="showLoader()"
type="radio"
:id="this.value"
:value="this.value"
class="position-absolute opacity-0"
v-on:click="showLoader()"
/>
<label
:for="this.value"
class="btn list-button d-flex align-items-center"
v-bind:class="[this.isLoading ? 'button-loader' : '']"
:for="this.value"
class="btn list-button d-flex align-items-center"
v-bind:class="[this.isLoading ? 'button-loader' : '']"
>
<span>{{ text }}</span>
<span>{{ text }}</span>
</label>
</div>
</div>
</template>
<script>
export default {
name: "radio",
props: [
"value",
"text"
],
props: ["value", "text"],
data() {
return {
isLoading: false,

View file

@ -1 +1 @@
test.todo('some test to be written in the future');
test.todo("some test to be written in the future");

View file

@ -47,7 +47,7 @@ export default {
</script>
<style lang="scss">
.radio-card {
input[type=radio] {
input[type="radio"] {
&:focus + label {
background-color: $white;
box-shadow: 0px 0px 0px 4px $blue;
@ -74,5 +74,4 @@ export default {
}
}
}
</style>
</style>

View file

@ -1 +1 @@
test.todo('some test to be written in the future');
test.todo("some test to be written in the future");

View file

@ -1,28 +1,36 @@
<template>
<div class="radiogroup radio-list-button d-flex flex-column w-100">
<input type="radio" v-bind:id="radioID" v-bind:name="groupName" v-bind:value="radioID">
<label role="radio" tabindex="0" aria-checked="false" v-bind:for="radioID" class="mb-2 d-flex align-items-center p-2"
v-on:click="showLoader()"
v-bind:class="[this.isLoading ? 'button-loader' : 'not-loading',this.isError ? 'error' : '']"
>{{radioID}}</label>
<p class="small">{{errorMessage}}</p>
<input
type="radio"
v-bind:id="radioID"
v-bind:name="groupName"
v-bind:value="radioID"
/>
<label
role="radio"
tabindex="0"
aria-checked="false"
v-bind:for="radioID"
class="mb-2 d-flex align-items-center p-2"
v-on:click="showLoader()"
v-bind:class="[
this.isLoading ? 'button-loader' : 'not-loading',
this.isError ? 'error' : '',
]"
>{{ radioID }}</label
>
<p class="small">{{ errorMessage }}</p>
</div>
</template>
<script>
export default {
name: "radioList",
props: [
"groupName",
"ariaLabelBy",
"radioID",
"errorMessage"
],
props: ["groupName", "ariaLabelBy", "radioID", "errorMessage"],
data() {
return {
isLoading: false,
isError: false
isError: false,
};
},
methods: {

View file

@ -1,11 +1,13 @@
process.env.VUE_APP_CONSUMER_API_GATEWAY = "https://consumerapidev.safelite.com";
process.env.VUE_APP_CONSUMER_API_GATEWAY =
"https://consumerapidev.safelite.com";
module.exports = {
outputDir: "dist/fmg",
publicPath: "/fmg",
css: {
loaderOptions: {
sass: { // Load Order Matters!!!
sass: {
// Load Order Matters!!!
prependData: `
@import "./node_modules/bootstrap/scss/functions";
@import "@/styles/uxVariables.scss";
@ -17,8 +19,8 @@ module.exports = {
@import "@/styles/commonRadioStyles.scss";
@import "@/styles/commonTypographyStyles.scss";
@import "@/styles/commonComponentStyles/ymmsCommonStyles.scss";
`
}
}
}
`,
},
},
},
};

View file

@ -5,7 +5,8 @@ module.exports = {
publicPath: "/fmg",
css: {
loaderOptions: {
sass: { // Load Order Matters!!!
sass: {
// Load Order Matters!!!
prependData: `
@import "./node_modules/bootstrap/scss/functions";
@import "@/styles/uxVariables.scss";
@ -17,8 +18,8 @@ module.exports = {
@import "@/styles/commonRadioStyles.scss";
@import "@/styles/commonTypographyStyles.scss";
@import "@/styles/commonComponentStyles/ymmsCommonStyles.scss";
`
}
}
}
`,
},
},
},
};