diff --git a/jest.config.js b/jest.config.js index e5ceb43e4..ec51cb6f7 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,9 +1,21 @@ module.exports = { + verbose: true, + coverageReporters: ["html", "text", "jest-junit"], preset: "@vue/cli-plugin-unit-jest", - transform: { - "^.+\\.vue$": "vue-jest", + transform: { "^.+\\.vue$": "vue-jest" }, + moduleFileExtensions: ["js", "vue"], + collectCoverageFrom: [ + "src/**/*.{js,vue}", + "!src/main.js", + "!src/constants/*.js", + "!src/router/**/*.js", + "!src/helpers/unit-test-helper.js", + "!src/layouts/component-test/component-test.vue" + ], //! means exclude from coverage. + testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], + coverageThreshold: { + global: { + statements: 60, + }, }, - testMatch : [ - "**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)" - ], }; diff --git a/package-lock.json b/package-lock.json index cda38bdec..0ea2e31ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "canvas-confetti": "^1.4.0", "core-js": "^3.6.5", "http-status-codes": "^2.1.4", + "jest-junit": "^13.0.0", "vue": "^3.0.0", "vue-router": "^4.0.11", "vuex": "^4.0.2", @@ -10957,6 +10958,58 @@ "node": ">= 6" } }, + "node_modules/jest-junit": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-13.0.0.tgz", + "integrity": "sha512-JSHR+Dhb32FGJaiKkqsB7AR3OqWKtldLd6ZH2+FJ8D4tsweb8Id8zEVReU4+OlrRO1ZluqJLQEETm+Q6/KilBg==", + "dependencies": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/jest-junit/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-junit/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-junit/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-junit/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/jest-leak-detector": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", @@ -11690,6 +11743,9 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, + "dependencies": { + "graceful-fs": "^4.1.6" + }, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -17947,6 +18003,7 @@ "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", "dev": true, "dependencies": { + "chokidar": "^3.4.1", "graceful-fs": "^4.1.2", "neo-async": "^2.5.0" }, @@ -18010,6 +18067,7 @@ "anymatch": "^2.0.0", "async-each": "^1.0.1", "braces": "^2.3.2", + "fsevents": "^1.2.7", "glob-parent": "^3.1.0", "inherits": "^2.0.3", "is-binary-path": "^1.0.0", @@ -18921,6 +18979,11 @@ "async-limiter": "~1.0.0" } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" + }, "node_modules/xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", @@ -27805,6 +27868,42 @@ "throat": "^4.0.0" } }, + "jest-junit": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-13.0.0.tgz", + "integrity": "sha512-JSHR+Dhb32FGJaiKkqsB7AR3OqWKtldLd6ZH2+FJ8D4tsweb8Id8zEVReU4+OlrRO1ZluqJLQEETm+Q6/KilBg==", + "requires": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, "jest-leak-detector": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", @@ -34352,6 +34451,11 @@ "async-limiter": "~1.0.0" } }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" + }, "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", diff --git a/package.json b/package.json index 1a4a03c8c..2fe60a35b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", - "test:unit": "vue-cli-service test:unit", + "test:unit": "vue-cli-service test:unit --coverage --ci", "lint": "vue-cli-service lint" }, "dependencies": { @@ -22,6 +22,7 @@ }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.0", + "jest-junit": "^13.0.0", "@vue/cli-plugin-eslint": "~4.5.0", "@vue/cli-plugin-unit-jest": "~4.5.0", "@vue/cli-service": "~4.5.0", diff --git a/src/App.vue b/src/App.vue index 57b5ffe58..a44ab87b7 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,4 +1,3 @@ - diff --git a/src/common-components/radio-question/radio-question.spec.js b/src/common-components/radio-question/radio-question.spec.js new file mode 100644 index 000000000..da58ea8d1 --- /dev/null +++ b/src/common-components/radio-question/radio-question.spec.js @@ -0,0 +1,26 @@ +import { shallowMount } from "@vue/test-utils"; +import radioQuestion from "@/common-components/radio-question/radio-question"; + +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"); + }); +}); diff --git a/src/common-components/radio-question/radio-question.vue b/src/common-components/radio-question/radio-question.vue new file mode 100644 index 000000000..2fb50f018 --- /dev/null +++ b/src/common-components/radio-question/radio-question.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/commonComponents/radioQuestion/radioQuestion.spec.js b/src/commonComponents/radioQuestion/radioQuestion.spec.js deleted file mode 100644 index a9ba7476e..000000000 --- a/src/commonComponents/radioQuestion/radioQuestion.spec.js +++ /dev/null @@ -1,22 +0,0 @@ -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) } - } - }); - - // 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'); - }) -}) \ No newline at end of file diff --git a/src/commonComponents/radioQuestion/radioQuestion.vue b/src/commonComponents/radioQuestion/radioQuestion.vue deleted file mode 100644 index 7e8b16c55..000000000 --- a/src/commonComponents/radioQuestion/radioQuestion.vue +++ /dev/null @@ -1,27 +0,0 @@ - - - diff --git a/src/constants/application-config.js b/src/constants/application-config.js new file mode 100644 index 000000000..4b80d25d1 --- /dev/null +++ b/src/constants/application-config.js @@ -0,0 +1,5 @@ +const applicationConfig = { + CONSUMER_APIGATEWAY_URL: process.env.VUE_APP_CONSUMER_API_GATEWAY, +}; + +export { applicationConfig }; diff --git a/src/constants/applicationConfig.js b/src/constants/applicationConfig.js deleted file mode 100644 index 78c0387c5..000000000 --- a/src/constants/applicationConfig.js +++ /dev/null @@ -1,5 +0,0 @@ -const applicationConfig = { -CONSUMER_APIGATEWAY_URL: process.env.VUE_APP_CONSUMER_API_GATEWAY -} - -export { applicationConfig } \ No newline at end of file diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index a390db3ec..9ba245c34 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -1,27 +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' - }, - GetModels: { - url: '/vehicle/api/v1/vehicle/Models', - method: 'POST' - }, - GetStyles: { - url: '/vehicle/api/v1/vehicle/Styles', - method: 'POST' - }, - GetPageData: { - 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 } \ No newline at end of file +export { endpoints }; diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js new file mode 100644 index 000000000..75478ba7e --- /dev/null +++ b/src/constants/store-actions.js @@ -0,0 +1,10 @@ +const storeActions = { + 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 }; diff --git a/src/constants/storeActions.js b/src/constants/storeActions.js deleted file mode 100644 index 5ef5a3157..000000000 --- a/src/constants/storeActions.js +++ /dev/null @@ -1,7 +0,0 @@ -const storeActions = { - GET_ROUTE_INFO_ACTION: "getRouteInfo", - GET_YEARS: 'getYears', - GET_PAGE_DATA: 'getMockPageData', -} - -export { storeActions } \ No newline at end of file diff --git a/src/constants/widget-names.js b/src/constants/widget-names.js new file mode 100644 index 000000000..bad1390c6 --- /dev/null +++ b/src/constants/widget-names.js @@ -0,0 +1,6 @@ +const widgetNames = { + PAGE_HEADER_WIDGET: "PageHeaderWidget", + RADIO_QUESTION_WIDGET: "RadioQuestionWidget", +}; + +export { widgetNames }; diff --git a/src/constants/widgetNames.js b/src/constants/widgetNames.js deleted file mode 100644 index 013083bcf..000000000 --- a/src/constants/widgetNames.js +++ /dev/null @@ -1,6 +0,0 @@ -const widgetNames = { - PAGE_HEADING_WIDGET: "PageHeadingWidget", - RADIO_QUESTION_WIDGET: "RadioQuestionWidget" -} - -export { widgetNames } \ No newline at end of file diff --git a/src/global-methods.js b/src/global-methods.js index 0b33cf613..9df098b7d 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -1,13 +1,14 @@ import axios from "axios"; -import { applicationConfig } from "@/constants/applicationConfig.js"; +import { applicationConfig } from "@/constants/application-config.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,8 +16,8 @@ export default { data: payloadAndAnalyticsData, crossDomain: true, responseType: {}, - }).then((response) => { - + }).then( + (response) => { if (response.status == httpStatusCodes.OK) { resolve(response); } else { @@ -30,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 { @@ -54,5 +53,5 @@ export default { } ); }); - } + }, }; diff --git a/src/global-methods.spec.js b/src/global-methods.spec.js index 6885a23e0..59fa15b77 100644 --- a/src/global-methods.spec.js +++ b/src/global-methods.spec.js @@ -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 - } -} \ No newline at end of file + return { + endpoint: endpoint, + }; +} diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js new file mode 100644 index 000000000..94027cc05 --- /dev/null +++ b/src/helpers/unit-test-helper.js @@ -0,0 +1,36 @@ +import { storeActions } from "@/constants/store-actions"; + +export function getMountOptions(mockData, cmsMockData = null) { + // 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) { + return Promise.resolve({ + data: actionFilterResult[0].data, + }); + } + }); + + if(cmsMockData){ + mocks.GetContentFromCms = jest.fn(); + mocks.GetContentFromCms.mockImplementation(() => + { + return cmsMockData; + }); + } + + // Mock store actions from js file + mocks.storeActions = storeActions; + const global = { + mocks: mocks, + }; + + return { global }; +} + diff --git a/src/helpers/unitTestHelper.js b/src/helpers/unitTestHelper.js deleted file mode 100644 index 417b47e43..000000000 --- a/src/helpers/unitTestHelper.js +++ /dev/null @@ -1,26 +0,0 @@ -import { storeActions } from "@/constants/storeActions"; - -export function getMountOptions(mockData) { - // 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) { - - return Promise.resolve({ - data: actionFilterResult[0].data - }); - } - }); - // Mock store actions from js file - mocks.storeActions = storeActions; - const global = { - mocks: mocks - }; - - return { global } -} \ No newline at end of file diff --git a/src/layouts/component-test/component-test.vue b/src/layouts/component-test/component-test.vue new file mode 100644 index 000000000..7351b2bff --- /dev/null +++ b/src/layouts/component-test/component-test.vue @@ -0,0 +1,112 @@ + + + diff --git a/src/layouts/not-found/not-found.vue b/src/layouts/not-found/not-found.vue new file mode 100644 index 000000000..6c4cc8e33 --- /dev/null +++ b/src/layouts/not-found/not-found.vue @@ -0,0 +1,3 @@ + diff --git a/src/layouts/notFound/notFound.vue b/src/layouts/notFound/notFound.vue deleted file mode 100644 index 954d1387c..000000000 --- a/src/layouts/notFound/notFound.vue +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/src/layouts/selectMake/selectMake.spec.js b/src/layouts/selectMake/selectMake.spec.js deleted file mode 100644 index 882a68129..000000000 --- a/src/layouts/selectMake/selectMake.spec.js +++ /dev/null @@ -1 +0,0 @@ -test.todo('some test to be written in the future'); \ No newline at end of file diff --git a/src/layouts/selectMake/selectMake.vue b/src/layouts/selectMake/selectMake.vue deleted file mode 100644 index 8821286a3..000000000 --- a/src/layouts/selectMake/selectMake.vue +++ /dev/null @@ -1,48 +0,0 @@ - - - diff --git a/src/layouts/selectModel/selectModel.spec.js b/src/layouts/selectModel/selectModel.spec.js deleted file mode 100644 index 882a68129..000000000 --- a/src/layouts/selectModel/selectModel.spec.js +++ /dev/null @@ -1 +0,0 @@ -test.todo('some test to be written in the future'); \ No newline at end of file diff --git a/src/layouts/selectModel/selectModel.vue b/src/layouts/selectModel/selectModel.vue deleted file mode 100644 index 4c0bd9b0d..000000000 --- a/src/layouts/selectModel/selectModel.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - diff --git a/src/layouts/selectStyle/selectStyle.spec.js b/src/layouts/selectStyle/selectStyle.spec.js deleted file mode 100644 index 882a68129..000000000 --- a/src/layouts/selectStyle/selectStyle.spec.js +++ /dev/null @@ -1 +0,0 @@ -test.todo('some test to be written in the future'); \ No newline at end of file diff --git a/src/layouts/selectStyle/selectStyle.vue b/src/layouts/selectStyle/selectStyle.vue deleted file mode 100644 index 731b0d8d9..000000000 --- a/src/layouts/selectStyle/selectStyle.vue +++ /dev/null @@ -1,47 +0,0 @@ - - - diff --git a/src/layouts/selectYear/selectYear.spec.js b/src/layouts/selectYear/selectYear.spec.js deleted file mode 100644 index 27b84ed5f..000000000 --- a/src/layouts/selectYear/selectYear.spec.js +++ /dev/null @@ -1,55 +0,0 @@ -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" - } - } - ] - } - }, - { - actionName: storeActions.GET_YEARS, - data: ['2023', '2022', '2021'] - } - ] - }; - - const mountOptions = getMountOptions(mockDataAndAction); - - // Act - const wrapper = shallowMount(selectYear, mountOptions); - await nextTick() - - // 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"); - }); - - -}) \ No newline at end of file diff --git a/src/layouts/selectYear/selectYear.vue b/src/layouts/selectYear/selectYear.vue deleted file mode 100644 index 3b633b005..000000000 --- a/src/layouts/selectYear/selectYear.vue +++ /dev/null @@ -1,78 +0,0 @@ - - - diff --git a/src/layouts/vehicle-year/vehicle-year.spec.js b/src/layouts/vehicle-year/vehicle-year.spec.js new file mode 100644 index 000000000..fbc3afedf --- /dev/null +++ b/src/layouts/vehicle-year/vehicle-year.spec.js @@ -0,0 +1,27 @@ +import { shallowMount, flushPromises } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import vehicleYear from "@/layouts/vehicle-year/vehicle-year.vue"; + +describe("vehicle-year.vue", () => { + test("vehicle-year.vue should render data from CMS", async () => { + + // Arrange + const cmsMockData = { + PageHeaderWidget: [{ HeaderText: "Select a year to get started" }], + RadioQuestionWidget: [{ QuestionText: "What year is your vehicle?" }], + } + + const mountOptions = getMountOptions({}, cmsMockData); + + // Act + const wrapper = shallowMount(vehicleYear, mountOptions); + await flushPromises(); + + // Assert + const header = await wrapper.find(".Header"); + expect(header.attributes("text")).toEqual("Select a year to get started"); + + const yearQuestion = await wrapper.findComponent({name: 'year-question'}); + expect(yearQuestion.attributes("questiontext")).toEqual("What year is your vehicle?"); + }); +}); diff --git a/src/layouts/vehicle-year/vehicle-year.vue b/src/layouts/vehicle-year/vehicle-year.vue new file mode 100644 index 000000000..0f40a57b6 --- /dev/null +++ b/src/layouts/vehicle-year/vehicle-year.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/layouts/vehicle-year/year-question/year-question.spec.js b/src/layouts/vehicle-year/year-question/year-question.spec.js new file mode 100644 index 000000000..a5ab50320 --- /dev/null +++ b/src/layouts/vehicle-year/year-question/year-question.spec.js @@ -0,0 +1,28 @@ +import { shallowMount, flushPromises } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { storeActions } from "@/constants/store-actions.js"; +import yearQuestion from "@/layouts/vehicle-year/year-question/year-question"; + +describe('year-question.vue', () => { + + test('year-question should call API to get years', async () => { + // Arrange + const mockDataAndAction = { + actionList: [{ actionName: storeActions.GET_VEHICLE_YEARS, data: ["2023", "2022", "2021"], + }, + ], + }; + + const mountOptions = getMountOptions(mockDataAndAction); + + // Act + const wrapper = shallowMount(yearQuestion, mountOptions); + await wrapper.setProps({questionText: 'What year is your vehicle?'}) + await flushPromises(); + + // Assert + const radioQuestion = await wrapper.findComponent({name: 'radioQuestion'}); + expect(radioQuestion.attributes('questiontext')).toBe("What year is your vehicle?"); + expect(radioQuestion.attributes('answers')).toBe('2023,2022,2021'); + }); +}); diff --git a/src/layouts/vehicle-year/year-question/year-question.vue b/src/layouts/vehicle-year/year-question/year-question.vue new file mode 100644 index 000000000..4aedb12df --- /dev/null +++ b/src/layouts/vehicle-year/year-question/year-question.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/main.js b/src/main.js index 784b51717..6f46d1802 100644 --- a/src/main.js +++ b/src/main.js @@ -1,9 +1,8 @@ import { createApp } from "vue"; import App from "./App.vue"; -import router from './router'; -import store from '@/store'; -import baseMixin from "@/mixins/baseMixin.js"; -//Bootstrap JavaScript +import router from "./router"; +import store from "@/store"; +import baseMixin from "@/mixins/base-mixin.js"; import "../node_modules/bootstrap/dist/js/bootstrap.js"; // Vue App Setup diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js new file mode 100644 index 000000000..81a191aa5 --- /dev/null +++ b/src/mixins/base-mixin.js @@ -0,0 +1,69 @@ +import { storeActions } from "@/constants/store-actions.js"; +import { widgetNames } from "@/constants/widget-names.js"; + +export default { + data(){ + return { + isCmsContentReady: false + } + }, + methods: { + // dispatchBlockingStoreAction(type, payload) { + // // globalMethods.showWaitingModal(true); + + // return this.dispatchNonBlockingStoreAction(type, payload).finally(() => { + // // globalMethods.showWaitingModal(false); + // }); + // }, + dispatchNonBlockingStoreAction(type, payload, encodePayload = false) { + // 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; + } + + pageDataFromCms[widget.Type] = [widget.Model]; + + } + }); + + // Our 'Page' is ready because we have data now + this.isCmsContentReady = true; + + return pageDataFromCms; + }); + }, + }, + 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]); + }); + } +} diff --git a/src/mixins/base-mixin.spec.js b/src/mixins/base-mixin.spec.js new file mode 100644 index 000000000..a6eb8d504 --- /dev/null +++ b/src/mixins/base-mixin.spec.js @@ -0,0 +1,109 @@ +import baseMixin from "@/mixins/base-mixin" +import { storeActions } from "@/constants/store-actions.js"; +import { widgetNames } from "@/constants/widget-names.js"; +import { flushPromises } from "@vue/test-utils"; + +describe("baseMixin.js", () => { + test('dispatchNonblockingStoreAction: calls dispatch with type and payload', () => { + const mixIn = getMixInInstance({}); + const type = {}; + const payload = {}; + + mixIn.methods.dispatchNonBlockingStoreAction(type, payload); + + expect(mixIn.methods.$store.dispatch).toBeCalledWith(type, payload); + }); + + test('dispatchNonblockingStoreAction: calls dispatch with type and payload, handles Uri encode', () => { + const mixIn = getMixInInstance({}); + const type = {}; + const payload = { make: 'Alfa Romeo/Chrysler' }; + + mixIn.methods.dispatchNonBlockingStoreAction(type, payload, true); + + expect(mixIn.methods.$store.dispatch).toBeCalledWith(type, payload); + }); + + test('GetContentFromCms: Should return mapped data and call dispatchNonblockingStoreAction', async () => { + const mixIn = getMixInInstance({}); + + // Mock dispatch action + mixIn.methods.dispatchNonBlockingStoreAction = jest.fn(); + mixIn.methods.dispatchNonBlockingStoreAction.mockImplementation((action) => { + if (action === 'getPageData') { + return Promise.resolve({ + data: { + Result: [ + { + Type: "PageConfigWidget", + Model: { + LayoutNames: [ + "None", + "vehicle-year" + ], + LayoutStyle: "vehicle-year" + } + }, + { + Type: "RadioQuestionWidget", + Model: { + "QuestionText": "What year is your vehicle?" + } + }, + { + Type: "RadioQuestionWidget", + Model: { + "QuestionText": "This is a second radio question" + } + }, + { + Type: "PageHeaderWidget", + Model: { + "HeaderText": "Select a year to get started" + } + } + ] + }, + }); + } + }); + + const result = await mixIn.methods.GetContentFromCms(); + await flushPromises(); + + + expect(mixIn.methods.dispatchNonBlockingStoreAction).toBeCalledWith(storeActions.GET_PAGE_DATA, { pageName: 'test-page'}); + + expect(result.PageHeaderWidget[0].HeaderText).toEqual('Select a year to get started'); + + }); +}) +function getMixInInstance({ isDispatchSuccess = true }) { + + // Mock Store + const store = { + dispatch: jest.fn() + } + + if (isDispatchSuccess) { + store.dispatch.mockReturnValue(Promise.resolve()) + } else { + store.dispatch.mockReturnValue(Promise.reject()) + } + + // Mock Route + const route = { + query: { + fmgPage: 'test-page' + } + }; + + // Attach mocks to mixin + const baseMixIn = baseMixin; + baseMixIn.methods.$route = route; + baseMixIn.methods.$store = store; + baseMixIn.methods.storeActions = storeActions; + baseMixIn.methods.widgetNames = widgetNames; + + return baseMixIn; +} \ No newline at end of file diff --git a/src/mixins/baseMixin.js b/src/mixins/baseMixin.js deleted file mode 100644 index 414d8bb47..000000000 --- a/src/mixins/baseMixin.js +++ /dev/null @@ -1,26 +0,0 @@ -import { storeActions } from "@/constants/storeActions.js"; -import { widgetNames } from "@/constants/widgetNames.js"; - -export default { - methods: { - dispatchBlockingStoreAction(type, payload) { - // globalMethods.showWaitingModal(true); - - return this.dispatchNonBlockingStoreAction(type, payload) - .finally(() => { - // globalMethods.showWaitingModal(false); - });; - }, - dispatchNonBlockingStoreAction(type, payload) { - return this.$store.dispatch(type, payload); - }, - }, - computed: { - storeActions() { - return storeActions; - }, - widgetNames(){ - return widgetNames; - } - }, -} \ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index 836a6256e..1042b093f 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,15 +1,15 @@ import { createWebHistory, createRouter } from "vue-router"; -import { storeActions } from "@/constants/storeActions.js"; +import { storeActions } from "@/constants/store-actions.js"; import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js"; -import ComponentTest from "@/layouts/componentTest/componentTest.vue"; -import NotFound from "@/layouts/notFound/notFound.vue"; +import ComponentTest from "@/layouts/component-test/component-test.vue"; +import NotFound from "@/layouts/not-found/not-found.vue"; 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: '/', // 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: `${jsonFromResponse[key].RelativeUrl}`, + 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, }); } diff --git a/src/store/index.js b/src/store/index.js index e861a5ff0..7bed83a55 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -10,103 +10,106 @@ export default createStore({ }), ], state: { - makes: [], - models: [], - styles: [], - year: "", - make: "", - model: "", - style: "", - slideTransition: "none", - carImg: - "https://s3.amazonaws.com/safelite-lab-vehicle-images/Evox/8963_cc0320_032_UG_white_2014_Ford_Focus_18029225538399034889.jpg", - blurImg: true, - }, - mutations: { - updateYear(state, data) { - state.year = data.year; - state.makes = data.makes.data; - state.slideTransition = "slide"; - }, - updateMake(state, data) { - state.make = data.make; - state.models = data.models.data; - state.slideTransition = "slide"; - }, - updateModel(state, data) { - state.model = data.model; - state.styles = data.styles.data; - state.slideTransition = "slide"; - }, - updateStyle(state, data) { - state.style = data.style; - state.carImg = - "https://s3.amazonaws.com/safelite-lab-vehicle-images/Evox/8963_cc0320_032_UG_white_2014_Ford_Focus_18029225538399034889.jpg"; - state.blurImg = false; - state.slideTransition = "slide"; - }, - removeStyle(state) { - state.style = ""; - state.blurImg = true; - state.carImg = - "https://s3.amazonaws.com/safelite-lab-vehicle-images/Evox/8963_cc0320_032_UG_white_2014_Ford_Focus_18029225538399034889.jpg"; - }, + order: { + vehicle: { + year: null, + make: null, + model: null, + style: null, + vin: null, + licensePlate: null, + carId: null, + evoxImageId: null, + hasSplitWindshieldOption: null, + hasBackglassSliderOption: null, + registration: { + rawAddress: null, + zipCode: null, + firstName: null, + lastName: null, + licensePlate: null + }, + damage: { + isRepair: null, + isReplacement: null, + numberOfChips: null, + glassToReplace: null, + problemGlassQuestions: null, + problemMoldingQuestions: null, + problemPropertyQuestions: null, + }, + items: null, + customer: { + emailAddress: null, + firstName: null, + lastName: null, + phoneNumber: { + isMobile: null, + optInSms: null, + } + }, + payment: { + isInsurance: null, + isCash: null, + }, + referral: { + referralSeqNum: null, + workOrderId: null + } + } + }, + applicationUser: { + experiments: null, + } }, + mutations: {}, actions: { - getYears(){ - return globalMethods.callHttpClient({ - method: endpoints.GetYears.method, - endpoint: endpoints.GetYears.url, - payload:{} - }); - }, - selectYear(context, { year }) { - return globalMethods.callHttpClient({ - method: endpoints.GetMakes.method, - endpoint: endpoints.GetMakes.url, - payload:{ - "Year": year - } - }); - }, - selectMake({ commit, state }, { make }) { - return globalMethods.callHttpClient({ - method: endpoints.GetModels.method, - endpoint: endpoints.GetModels.url, - payload:{ - "Year": state.year, - "Make": make - } - }); - }, - selectModel({ commit, state }, { model }) { - return globalMethods.callHttpClient({ - method: endpoints.GetStyles.method, - endpoint: endpoints.GetStyles.url, - payload:{ - "Year": state.year, - "Make": state.make, - "Model": model - } - }); - }, - getRouteInfo(context, { relativeUrl }) { - return globalMethods.callHttpClient({ - method: endpoints.GetRouteInfoEndpoint.method, - endpoint: endpoints.GetRouteInfoEndpoint.url, - payload: { - relativeUrl: relativeUrl, - }, - }); - }, - // For mock data purposes only - getMockPageData(context, { relativeUrl }) { - return globalMethods.callMockHttpClient({ - method: endpoints.GetPageData.method, - endpoint: relativeUrl, - payload: { - }, - }); - }, + // Vehicle API Actions + getVehicleYears(context) { + return globalMethods.callHttpClient({ + 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.GetRouteInfo.method, + endpoint: endpoints.GetRouteInfo.url, + payload: { + pageName: pageName, + }, + }); + }, + getPageData(context, { pageName }) { + return globalMethods.callHttpClient({ + method: endpoints.GetPageData.method, + endpoint: `${endpoints.GetPageData.url}/${pageName}`, + payload: {}, + }); + }, }, }); diff --git a/src/styles/commonButtonStyles.scss b/src/styles/common-button-styles.scss similarity index 100% rename from src/styles/commonButtonStyles.scss rename to src/styles/common-button-styles.scss diff --git a/src/styles/commonComponentStyles/ymmsCommonStyles.scss b/src/styles/common-component-styles/ymms-common-styles.scss similarity index 100% rename from src/styles/commonComponentStyles/ymmsCommonStyles.scss rename to src/styles/common-component-styles/ymms-common-styles.scss diff --git a/src/styles/commonRadioStyles.scss b/src/styles/common-radio-styles.scss similarity index 100% rename from src/styles/commonRadioStyles.scss rename to src/styles/common-radio-styles.scss diff --git a/src/styles/commonStyles.scss b/src/styles/common-styles.scss similarity index 100% rename from src/styles/commonStyles.scss rename to src/styles/common-styles.scss diff --git a/src/styles/commonTypographyStyles.scss b/src/styles/common-typography-styles.scss similarity index 100% rename from src/styles/commonTypographyStyles.scss rename to src/styles/common-typography-styles.scss diff --git a/src/styles/uxVariables.scss b/src/styles/ux-variables.scss similarity index 100% rename from src/styles/uxVariables.scss rename to src/styles/ux-variables.scss diff --git a/src/uxComponents/alert/alert.spec.js b/src/ux-components/alert/alert.spec.js similarity index 100% rename from src/uxComponents/alert/alert.spec.js rename to src/ux-components/alert/alert.spec.js diff --git a/src/uxComponents/alert/alert.vue b/src/ux-components/alert/alert.vue similarity index 100% rename from src/uxComponents/alert/alert.vue rename to src/ux-components/alert/alert.vue diff --git a/src/ux-components/button-primary/button-primary.spec.js b/src/ux-components/button-primary/button-primary.spec.js new file mode 100644 index 000000000..3d0843e10 --- /dev/null +++ b/src/ux-components/button-primary/button-primary.spec.js @@ -0,0 +1 @@ +test.todo("some test to be written in the future"); diff --git a/src/uxComponents/buttonPrimary/buttonPrimary.vue b/src/ux-components/button-primary/button-primary.vue similarity index 90% rename from src/uxComponents/buttonPrimary/buttonPrimary.vue rename to src/ux-components/button-primary/button-primary.vue index 9741d9c49..1f5738cb8 100644 --- a/src/uxComponents/buttonPrimary/buttonPrimary.vue +++ b/src/ux-components/button-primary/button-primary.vue @@ -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 }} @@ -15,11 +15,11 @@ export default { name: "buttonPrimary", props: { buttonText: String, - isDisabled: Boolean + isDisabled: Boolean, }, data() { return { - isLoading: false + isLoading: false, }; }, methods: { diff --git a/src/ux-components/button-secondary/button-secondary.spec.js b/src/ux-components/button-secondary/button-secondary.spec.js new file mode 100644 index 000000000..3d0843e10 --- /dev/null +++ b/src/ux-components/button-secondary/button-secondary.spec.js @@ -0,0 +1 @@ +test.todo("some test to be written in the future"); diff --git a/src/uxComponents/buttonSecondary/buttonSecondary.vue b/src/ux-components/button-secondary/button-secondary.vue similarity index 94% rename from src/uxComponents/buttonSecondary/buttonSecondary.vue rename to src/ux-components/button-secondary/button-secondary.vue index 19961efa0..3840922d4 100644 --- a/src/uxComponents/buttonSecondary/buttonSecondary.vue +++ b/src/ux-components/button-secondary/button-secondary.vue @@ -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 }} @@ -14,7 +14,7 @@ export default { name: "buttonSecondary", props: { - buttonText: String + buttonText: String, }, data() { return { diff --git a/src/ux-components/header/header.spec.js b/src/ux-components/header/header.spec.js new file mode 100644 index 000000000..f5a423803 --- /dev/null +++ b/src/ux-components/header/header.spec.js @@ -0,0 +1,16 @@ +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", + }, + }); + + // Assert + expect(wrapper.find("span").text()).toContain("Header Content"); + }); +}); diff --git a/src/ux-components/header/header.vue b/src/ux-components/header/header.vue new file mode 100644 index 000000000..621e4c917 --- /dev/null +++ b/src/ux-components/header/header.vue @@ -0,0 +1,16 @@ + + + diff --git a/src/ux-components/list-button/list-button.spec.js b/src/ux-components/list-button/list-button.spec.js new file mode 100644 index 000000000..3d0843e10 --- /dev/null +++ b/src/ux-components/list-button/list-button.spec.js @@ -0,0 +1 @@ +test.todo("some test to be written in the future"); diff --git a/src/uxComponents/listButton/listButton.vue b/src/ux-components/list-button/list-button.vue similarity index 74% rename from src/uxComponents/listButton/listButton.vue rename to src/ux-components/list-button/list-button.vue index e6297fe60..2580b0f83 100644 --- a/src/uxComponents/listButton/listButton.vue +++ b/src/ux-components/list-button/list-button.vue @@ -3,8 +3,11 @@ @@ -16,12 +19,12 @@ export default { name: "listButton", props: { buttonText: String, - errorText: String + errorText: String, }, data() { return { isLoading: false, - isError: false + isError: false, }; }, methods: { diff --git a/src/ux-components/radio-card/radio-card.spec.js b/src/ux-components/radio-card/radio-card.spec.js new file mode 100644 index 000000000..3d0843e10 --- /dev/null +++ b/src/ux-components/radio-card/radio-card.spec.js @@ -0,0 +1 @@ +test.todo("some test to be written in the future"); diff --git a/src/uxComponents/radioCard/radioCard.vue b/src/ux-components/radio-card/radio-card.vue similarity index 97% rename from src/uxComponents/radioCard/radioCard.vue rename to src/ux-components/radio-card/radio-card.vue index fbf55aa77..0789827ef 100644 --- a/src/uxComponents/radioCard/radioCard.vue +++ b/src/ux-components/radio-card/radio-card.vue @@ -47,7 +47,7 @@ export default { \ No newline at end of file + diff --git a/src/ux-components/radio-list/radio-list.spec.js b/src/ux-components/radio-list/radio-list.spec.js new file mode 100644 index 000000000..3d0843e10 --- /dev/null +++ b/src/ux-components/radio-list/radio-list.spec.js @@ -0,0 +1 @@ +test.todo("some test to be written in the future"); diff --git a/src/ux-components/radio-list/radio-list.vue b/src/ux-components/radio-list/radio-list.vue new file mode 100644 index 000000000..b6a02eca2 --- /dev/null +++ b/src/ux-components/radio-list/radio-list.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/ux-components/radio/radio.spec.js b/src/ux-components/radio/radio.spec.js new file mode 100644 index 000000000..35ddfdab7 --- /dev/null +++ b/src/ux-components/radio/radio.spec.js @@ -0,0 +1,23 @@ +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", + }, + }); + + // 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", + }); + }); +}); diff --git a/src/ux-components/radio/radio.vue b/src/ux-components/radio/radio.vue new file mode 100644 index 000000000..ac005bca4 --- /dev/null +++ b/src/ux-components/radio/radio.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/uxComponents/buttonPrimary/buttonPrimary.spec.js b/src/uxComponents/buttonPrimary/buttonPrimary.spec.js deleted file mode 100644 index 882a68129..000000000 --- a/src/uxComponents/buttonPrimary/buttonPrimary.spec.js +++ /dev/null @@ -1 +0,0 @@ -test.todo('some test to be written in the future'); \ No newline at end of file diff --git a/src/uxComponents/buttonSecondary/buttonSecondary.spec.js b/src/uxComponents/buttonSecondary/buttonSecondary.spec.js deleted file mode 100644 index 882a68129..000000000 --- a/src/uxComponents/buttonSecondary/buttonSecondary.spec.js +++ /dev/null @@ -1 +0,0 @@ -test.todo('some test to be written in the future'); \ No newline at end of file diff --git a/src/uxComponents/confetti/confetti.spec.js b/src/uxComponents/confetti/confetti.spec.js deleted file mode 100644 index 882a68129..000000000 --- a/src/uxComponents/confetti/confetti.spec.js +++ /dev/null @@ -1 +0,0 @@ -test.todo('some test to be written in the future'); \ No newline at end of file diff --git a/src/uxComponents/confetti/confetti.vue b/src/uxComponents/confetti/confetti.vue deleted file mode 100644 index 38fc69d10..000000000 --- a/src/uxComponents/confetti/confetti.vue +++ /dev/null @@ -1,44 +0,0 @@ - diff --git a/src/uxComponents/header/header.spec.js b/src/uxComponents/header/header.spec.js deleted file mode 100644 index d02c78d9f..000000000 --- a/src/uxComponents/header/header.spec.js +++ /dev/null @@ -1,16 +0,0 @@ -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' - } - }); - - // Assert - expect(wrapper.find('span').text()).toContain("Header Content"); - }) -}); \ No newline at end of file diff --git a/src/uxComponents/header/header.vue b/src/uxComponents/header/header.vue deleted file mode 100644 index a2a68eeb7..000000000 --- a/src/uxComponents/header/header.vue +++ /dev/null @@ -1,16 +0,0 @@ - - - \ No newline at end of file diff --git a/src/uxComponents/listButton/listButton.spec.js b/src/uxComponents/listButton/listButton.spec.js deleted file mode 100644 index e360d0fc1..000000000 --- a/src/uxComponents/listButton/listButton.spec.js +++ /dev/null @@ -1 +0,0 @@ -test.todo('some test to be written in the future'); diff --git a/src/uxComponents/radio/radio.spec.js b/src/uxComponents/radio/radio.spec.js deleted file mode 100644 index ba59e2650..000000000 --- a/src/uxComponents/radio/radio.spec.js +++ /dev/null @@ -1,23 +0,0 @@ -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' - } - }); - - // 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' - }); - }) -}) \ No newline at end of file diff --git a/src/uxComponents/radio/radio.vue b/src/uxComponents/radio/radio.vue deleted file mode 100644 index 1f4e63f39..000000000 --- a/src/uxComponents/radio/radio.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/src/uxComponents/radioCard/radioCard.spec.js b/src/uxComponents/radioCard/radioCard.spec.js deleted file mode 100644 index 882a68129..000000000 --- a/src/uxComponents/radioCard/radioCard.spec.js +++ /dev/null @@ -1 +0,0 @@ -test.todo('some test to be written in the future'); \ No newline at end of file diff --git a/src/uxComponents/radioList/radioList.spec.js b/src/uxComponents/radioList/radioList.spec.js deleted file mode 100644 index 882a68129..000000000 --- a/src/uxComponents/radioList/radioList.spec.js +++ /dev/null @@ -1 +0,0 @@ -test.todo('some test to be written in the future'); \ No newline at end of file diff --git a/vue.config.js b/vue.config.js index 2838ed844..99d40f6ca 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,35 +1,27 @@ -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", - devServer: { - port: 8080, - proxy: { - "api/v1/content*": { - target: "https://localhost:44360/", - ws: false, - changeOrigin: true, - }, - }, - }, css: { loaderOptions: { - sass: { // Load Order Matters!!! + sass: { + // Load Order Matters!!! prependData: ` @import "./node_modules/bootstrap/scss/functions"; - @import "@/styles/uxVariables.scss"; + @import "@/styles/ux-variables.scss"; @import "./node_modules/bootstrap/scss/variables"; @import "./node_modules/bootstrap/scss/mixins"; @import "@/styles/mixins/customMixins"; @import "./node_modules/bootstrap/scss/bootstrap"; - @import "@/styles/commonStyles.scss"; - @import "@/styles/commonButtonStyles.scss"; - @import "@/styles/commonRadioStyles.scss"; - @import "@/styles/commonTypographyStyles.scss"; - @import "@/styles/commonComponentStyles/ymmsCommonStyles.scss"; - ` - } - } - } + @import "@/styles/common-styles.scss"; + @import "@/styles/common-button-styles.scss"; + @import "@/styles/common-radio-styles.scss"; + @import "@/styles/common-typography-styles.scss"; + @import "@/styles/common-component-styles/ymms-common-styles.scss"; + `, + }, + }, + }, }; diff --git a/vue.release.config.js b/vue.release.config.js index 4a0145d30..99fcfcde3 100644 --- a/vue.release.config.js +++ b/vue.release.config.js @@ -5,21 +5,22 @@ 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"; + @import "@/styles/ux-variables.scss"; @import "./node_modules/bootstrap/scss/variables"; @import "./node_modules/bootstrap/scss/mixins"; @import "@/styles/mixins/customMixins"; @import "./node_modules/bootstrap/scss/bootstrap"; - @import "@/styles/commonStyles.scss"; - @import "@/styles/commonButtonStyles.scss"; - @import "@/styles/commonRadioStyles.scss"; - @import "@/styles/commonTypographyStyles.scss"; - @import "@/styles/commonComponentStyles/ymmsCommonStyles.scss"; - ` - } - } - } + @import "@/styles/common-styles.scss"; + @import "@/styles/common-button-styles.scss"; + @import "@/styles/common-radio-styles.scss"; + @import "@/styles/common-typography-styles.scss"; + @import "@/styles/common-component-styles/ymms-common-styles.scss"; + `, + }, + }, + }, };