Merge branch 'develop' into csr-116-message-component
This commit is contained in:
commit
6c5dc5af3d
27 changed files with 571 additions and 349 deletions
3
src/assets/img/icons/back-forward.svg
Normal file
3
src/assets/img/icons/back-forward.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45.6 36.1" xml:space="preserve">
|
||||
<path d="M43.6 0H18.1c-.4 0-.8.1-1.1.4l-.3.3-16 16c-.8.8-.8 2 0 2.8l16 16 .3.3c.3.2.7.4 1.1.4h25.5c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2zm-3.4 28.1-1.4 1.4-10-10-10 10-1.4-1.4 10-10-10-10 1.4-1.4 10 10 10-10L40.2 8l-10 10 10 10.1z" fill="#8e9292"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 338 B |
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
describe("baseTemplate.vue", () => {
|
||||
it("Is a test", () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
<template>
|
||||
<div class="select-car sticky-lg-top py-4">
|
||||
<div class="select-car-form overflow-hidden p-3 rounded">
|
||||
<div class="car_info text-center">
|
||||
<div class="car-image mb-3">
|
||||
<img
|
||||
class="vehicle-image img-fluid"
|
||||
:class="{ blur: blurImg }"
|
||||
:src="carImg"
|
||||
/>
|
||||
</div>
|
||||
<div class="current_car_info">
|
||||
<transition appear name="fade">
|
||||
<div
|
||||
class="current_car_info-text"
|
||||
v-on:click="backFunction ? backFunction() : null"
|
||||
>
|
||||
<span class="text-center text-secondary fs-5 d-block">{{
|
||||
this.currentCarInfo
|
||||
}}</span>
|
||||
<span v-if="style" class="text-center text-secondary fs-6 mt-2">{{
|
||||
style
|
||||
}}</span>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
<transition appear :name="slideTransition">
|
||||
<div class="needed_car_info d-flex overflow-hidden mt-4 mb-3">
|
||||
<span class="text-center fs-6 fw-bold needed_car_info-text">{{
|
||||
this.neededCarInfo
|
||||
}}</span>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
<transition appear :name="slideTransition">
|
||||
<slot></slot>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
|
||||
export default {
|
||||
name: "BaseTemplate",
|
||||
computed: {
|
||||
...mapState(["slideTransition", "carImg", "blurImg", "style"]),
|
||||
},
|
||||
props: {
|
||||
currentCarInfo: String,
|
||||
neededCarInfo: String,
|
||||
backFunction: Function,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -1 +0,0 @@
|
|||
test.todo('some test to be written in the future');
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<template>
|
||||
<form class="list-view d-flex">
|
||||
<div class="car_list">
|
||||
<div v-for="attritbute in attritbutes" :key="attritbute" class="mb-2">
|
||||
<buttonPrimary :buttonText="attritbute" v-on:click="selectAttribute(attritbute)" buttonType="btn-funnel" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import buttonPrimary from "@/uxComponents/buttonPrimary/buttonPrimary";
|
||||
|
||||
export default {
|
||||
name: "CarAttributes",
|
||||
props: {
|
||||
attritbutes: Array,
|
||||
selectAttribute: Function,
|
||||
},
|
||||
components: {
|
||||
buttonPrimary,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
22
src/commonComponents/radioQuestion/radioQuestion.spec.js
Normal file
22
src/commonComponents/radioQuestion/radioQuestion.spec.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
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');
|
||||
})
|
||||
})
|
||||
27
src/commonComponents/radioQuestion/radioQuestion.vue
Normal file
27
src/commonComponents/radioQuestion/radioQuestion.vue
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<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>
|
||||
</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>
|
||||
|
||||
<script>
|
||||
import radio from "@/uxComponents/radio/radio";
|
||||
export default {
|
||||
name: "radio-question",
|
||||
props: {
|
||||
questionText: String,
|
||||
answers: Array,
|
||||
chooseAnswer: Function
|
||||
},
|
||||
components: {
|
||||
radio
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -2,6 +2,25 @@ 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'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
const storeActions = {
|
||||
GET_ROUTE_INFO_ACTION: "getRouteInfo",
|
||||
GET_YEARS: 'getYears',
|
||||
GET_PAGE_DATA: 'getMockPageData',
|
||||
}
|
||||
|
||||
export { storeActions }
|
||||
|
|
@ -11,7 +11,7 @@ export default {
|
|||
|
||||
axios({
|
||||
method: method,
|
||||
url: `${apiGatewayUrl}${endpoint}`,
|
||||
url: apiGatewayUrl + endpoint,
|
||||
data: payloadAndAnalyticsData,
|
||||
crossDomain: true,
|
||||
responseType: {},
|
||||
|
|
@ -29,4 +29,30 @@ export default {
|
|||
);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/* istanbul ignore next */
|
||||
callMockHttpClient({ method, endpoint}) {
|
||||
// For Mock use only!
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
axios({
|
||||
method: method,
|
||||
url: endpoint,
|
||||
crossDomain: true,
|
||||
responseType: {},
|
||||
}).then((response) => {
|
||||
|
||||
if (response.status == httpStatusCodes.OK) {
|
||||
resolve(response);
|
||||
} else {
|
||||
reject(response);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
return reject(error.response);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
73
src/global-methods.spec.js
Normal file
73
src/global-methods.spec.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import globalMethods from "@/global-methods";
|
||||
import axios from 'axios';
|
||||
|
||||
//Mock external dependencies
|
||||
jest.mock('axios');
|
||||
|
||||
it("Global Methods - Call Http Client - Should Resolve Promise", () => {
|
||||
//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);
|
||||
});
|
||||
});
|
||||
|
||||
it("Global Methods - Call Http Client - Should Reject Promise", () => {
|
||||
//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);
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocksForHttpClient({ endpoint = null, isError = false, additionalData = null }) {
|
||||
|
||||
//Clear node module
|
||||
axios.mockClear();
|
||||
|
||||
// Success Response
|
||||
const response = {
|
||||
status: 200,
|
||||
data: {
|
||||
message: 'Success',
|
||||
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);
|
||||
}
|
||||
|
||||
return {
|
||||
endpoint: endpoint
|
||||
}
|
||||
}
|
||||
26
src/helpers/unitTestHelper.js
Normal file
26
src/helpers/unitTestHelper.js
Normal file
|
|
@ -0,0 +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 = {};
|
||||
|
||||
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 }
|
||||
}
|
||||
|
|
@ -158,5 +158,10 @@ export default {
|
|||
radioList,
|
||||
alert
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
years: [2023, 2022, 2021, 2020],
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
test.todo('some test to be written in the future');
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<baseTemplate
|
||||
:currentCarInfo="year + ' ' + make + ' ' + model"
|
||||
neededCarInfo="What is your damage?"
|
||||
>
|
||||
<div class="damage-section text-center">
|
||||
<div class="choose-damage row">
|
||||
<div class="col">
|
||||
<radioCard />
|
||||
</div>
|
||||
<div class="col">
|
||||
<radioCard />
|
||||
</div>
|
||||
<div class="col">
|
||||
<radioCard />
|
||||
</div>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div v-if="damage" class="how-bad mt-3">
|
||||
<span class="text-center fs-6 fw-bold">How bad is it?</span>
|
||||
<div class="choose-how-bad row mt-2">
|
||||
<div class="col">
|
||||
<radioCard />
|
||||
</div>
|
||||
<div class="col">
|
||||
<radioCard />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<div class="next-action row">
|
||||
<div class="col">
|
||||
<div v-on:click="goBack" class="change">
|
||||
<span>Change Vehicle</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</baseTemplate>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import baseTemplate from "@/commonComponents/baseTemplate/baseTemplate";
|
||||
import radioCard from "@/uxComponents/radioCard/radioCard";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
export default {
|
||||
name: "SelectCar",
|
||||
computed: {
|
||||
...mapState(["year", "make", "model"]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
damage: "",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
chooseDamage(damage) {
|
||||
this.damage = damage;
|
||||
console.log(this.damage);
|
||||
},
|
||||
goBack() {
|
||||
this.$store.state.slideTransition = "slide_reverse";
|
||||
this.$store.commit("removeStyle");
|
||||
this.$router.push(
|
||||
`/select-style?year=${this.$store.state.year}&make=${this.$store.state.make}`
|
||||
);
|
||||
},
|
||||
},
|
||||
components: {
|
||||
baseTemplate,
|
||||
radioCard,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -1,14 +1,23 @@
|
|||
<template>
|
||||
<div>
|
||||
<baseTemplate :currentCarInfo="year" neededCarInfo="What make is your vehicle?" :backFunction="goBack">
|
||||
<carAttributes :attritbutes="makes" :selectAttribute="selectMake" />
|
||||
</baseTemplate>
|
||||
</div>
|
||||
<div class="select-car overflow-hidden">
|
||||
<div class="select-car-form rounded text-center">
|
||||
<Header
|
||||
:text="year"
|
||||
/>
|
||||
<radioQuestion
|
||||
questionText="What is the make of your vehicle?"
|
||||
:answers="makes"
|
||||
:chooseAnswer="selectMake"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import baseTemplate from "@/commonComponents/baseTemplate/baseTemplate";
|
||||
import carAttributes from "@/commonComponents/carAttributes/carAttributes";
|
||||
import radioQuestion from "@/commonComponents/radioQuestion/radioQuestion";
|
||||
import Header from "@/uxComponents/header/header";
|
||||
import store from "@/store";
|
||||
import router from "@/router";
|
||||
import {
|
||||
mapState
|
||||
} from "vuex";
|
||||
|
|
@ -20,7 +29,11 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
selectMake(make) {
|
||||
this.$store.dispatch("selectMake", make);
|
||||
this.dispatchNonBlockingStoreAction("selectMake", { make: make }).then( (response) => {
|
||||
const models = response;
|
||||
store.commit('updateMake', {make, models});
|
||||
router.push(`/select-model?year=${store.year}&make=${make}`);
|
||||
});
|
||||
},
|
||||
goBack() {
|
||||
this.$store.state.slideTransition = "slide_reverse";
|
||||
|
|
@ -28,8 +41,8 @@ export default {
|
|||
},
|
||||
},
|
||||
components: {
|
||||
baseTemplate,
|
||||
carAttributes,
|
||||
radioQuestion,
|
||||
Header,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,23 @@
|
|||
<template>
|
||||
<div>
|
||||
<baseTemplate
|
||||
:currentCarInfo="year + ' ' + make"
|
||||
:neededCarInfo="'What is the model of your ' + make + '?'"
|
||||
:backFunction="goBack"
|
||||
>
|
||||
<carAttributes :attritbutes="models" :selectAttribute="selectModel" />
|
||||
</baseTemplate>
|
||||
<div class="select-car overflow-hidden">
|
||||
<div class="select-car-form rounded text-center">
|
||||
<Header
|
||||
:text="year + ' ' + make"
|
||||
/>
|
||||
<radioQuestion
|
||||
:questionText="'What is the model of your ' + make + '?'"
|
||||
:answers="models"
|
||||
:chooseAnswer="selectModel"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import baseTemplate from "@/commonComponents/baseTemplate/baseTemplate";
|
||||
import carAttributes from "@/commonComponents/carAttributes/carAttributes";
|
||||
import radioQuestion from "@/commonComponents/radioQuestion/radioQuestion";
|
||||
import Header from "@/uxComponents/header/header";
|
||||
import store from "@/store";
|
||||
import router from "@/router";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
export default {
|
||||
|
|
@ -22,16 +27,20 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
selectModel(model) {
|
||||
this.$store.dispatch("selectModel", model);
|
||||
this.dispatchNonBlockingStoreAction("selectModel", { model: model }).then( (response) => {
|
||||
const styles = response;
|
||||
store.commit("updateModel", { model, styles });
|
||||
router.push(`/select-style?year=${store.year}&make=${store.make}&model=${model}`);
|
||||
});
|
||||
},
|
||||
goBack() {
|
||||
this.$store.state.slideTransition = "slide_reverse";
|
||||
this.$router.push(`/select-make?year=${this.$store.state.year}`);
|
||||
this.$router.push(`/select-make?year=${store.year}`);
|
||||
},
|
||||
},
|
||||
components: {
|
||||
baseTemplate,
|
||||
carAttributes,
|
||||
radioQuestion,
|
||||
Header,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,23 @@
|
|||
<template>
|
||||
<div>
|
||||
<baseTemplate
|
||||
:currentCarInfo="year + ' ' + make + ' ' + model"
|
||||
:neededCarInfo="'What style is your ' + model + '?'"
|
||||
:backFunction="goBack"
|
||||
>
|
||||
<carAttributes :attritbutes="styles" :selectAttribute="selectStyle" />
|
||||
</baseTemplate>
|
||||
<div class="select-car overflow-hidden">
|
||||
<div class="select-car-form rounded text-center">
|
||||
<Header
|
||||
:text="year + ' ' + make + ' ' + model"
|
||||
/>
|
||||
<radioQuestion
|
||||
:questionText="'What style is your ' + model + '?'"
|
||||
:answers="styles"
|
||||
:chooseAnswer="selectStyle"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import baseTemplate from "@/commonComponents/baseTemplate/baseTemplate";
|
||||
import carAttributes from "@/commonComponents/carAttributes/carAttributes";
|
||||
import radioQuestion from "@/commonComponents/radioQuestion/radioQuestion";
|
||||
import Header from "@/uxComponents/header/header";
|
||||
import store from "@/store";
|
||||
import router from "@/router";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
export default {
|
||||
|
|
@ -22,18 +27,21 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
selectStyle(style) {
|
||||
this.$store.dispatch("selectStyle", style);
|
||||
store.commit("updateStyle", { style });
|
||||
router.push(
|
||||
`/select-damage?year=${store.year}&make=${store.make}&model=${store.model}&style=${style}`
|
||||
);
|
||||
},
|
||||
goBack() {
|
||||
this.$store.state.slideTransition = "slide_reverse";
|
||||
this.$router.push(
|
||||
`/select-model?year=${this.$store.state.year}&make=${this.$store.state.make}`
|
||||
`/select-model?year=${store.year}&make=${store.make}`
|
||||
);
|
||||
},
|
||||
},
|
||||
components: {
|
||||
baseTemplate,
|
||||
carAttributes,
|
||||
radioQuestion,
|
||||
Header,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1 +1,55 @@
|
|||
test.todo('some test to be written in the future');
|
||||
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");
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
|
|
@ -1,60 +1,78 @@
|
|||
<template>
|
||||
<div>
|
||||
<baseTemplate :currentCarInfo="pageHeader.Text" :neededCarInfo="radioQuestion.Question">
|
||||
<carAttributes :attritbutes="years" :selectAttribute="selectYear" />
|
||||
</baseTemplate>
|
||||
</div>
|
||||
<div class="select-car">
|
||||
<div class="select-car-form rounded text-center">
|
||||
|
||||
<Header
|
||||
:text="pageHeader.Text" class="Header"
|
||||
/>
|
||||
<radioQuestion
|
||||
class="radioQuestion"
|
||||
:questionText="radioQuestion.Question"
|
||||
:answers="this.years"
|
||||
:chooseAnswer="selectYear"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import baseTemplate from "@/commonComponents/baseTemplate/baseTemplate";
|
||||
import carAttributes from "@/commonComponents/carAttributes/carAttributes";
|
||||
import axios from "axios";
|
||||
import radioQuestion from "@/commonComponents/radioQuestion/radioQuestion";
|
||||
import Header from "@/uxComponents/header/header";
|
||||
import store from "@/store";
|
||||
import router from "@/router";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
export default {
|
||||
name: "SelectCar",
|
||||
data() {
|
||||
return {
|
||||
years: [],
|
||||
pageHeader: {},
|
||||
radioQuestion: {}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
axios.get("https://mockey.qa.sagaws.net/service/years").then((response) => {
|
||||
this.years = response.data.Result;
|
||||
});
|
||||
name: "SelectYear",
|
||||
data() {
|
||||
return {
|
||||
years: [],
|
||||
pageHeader: {},
|
||||
radioQuestion: {}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["slideTransition", "carImg", "blurImg", "style"]),
|
||||
},
|
||||
mounted() {
|
||||
// Mocking Sitefinity data to (For Page Header and Radio Question)
|
||||
this.dispatchNonBlockingStoreAction(this.storeActions.GET_PAGE_DATA, {relativeUrl: 'https://mockey.qa.sagaws.net/service/content/selectYear'})
|
||||
.then( (response) => {
|
||||
response.data.Result.forEach((m) => {
|
||||
switch (m.Type) {
|
||||
case 'PageHeadingWidget': {
|
||||
this.pageHeader = m.Model;
|
||||
break;
|
||||
}
|
||||
case 'RadioQuestionWidget': {
|
||||
this.radioQuestion = m.Model;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Sample Call to Mockey to represent real data being sent back from the API, and how the modles are supposed to
|
||||
// be prosessed and passed to child components.
|
||||
axios.get("https://mockey.qa.sagaws.net/service/content/selectYear").then((response) => {
|
||||
|
||||
response.data.Result.forEach((m) => {
|
||||
switch (m.Type) {
|
||||
case this.widgetNames.PAGE_HEADING_WIDGET: {
|
||||
this.pageHeader = m.Model;
|
||||
break;
|
||||
}
|
||||
case this.widgetNames.RADIO_QUESTION_WIDGET: {
|
||||
this.radioQuestion = m.Model;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
selectYear(year) {
|
||||
this.$store.dispatch("selectYear", year);
|
||||
},
|
||||
},
|
||||
components: {
|
||||
baseTemplate,
|
||||
carAttributes,
|
||||
},
|
||||
// Getting Years list
|
||||
this.dispatchNonBlockingStoreAction(this.storeActions.GET_YEARS)
|
||||
.then( (response) => {
|
||||
this.years = response.data;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
selectYear(year) {
|
||||
this.dispatchNonBlockingStoreAction("selectYear", { year: year }).then( (response) => {
|
||||
const makes = response;
|
||||
store.commit('updateYear', {year, makes});
|
||||
router.push(`select-make?year=${year}`);
|
||||
});
|
||||
}
|
||||
},
|
||||
components: {
|
||||
radioQuestion,
|
||||
Header,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import { createStore } from "vuex";
|
||||
import { endpoints } from "@/constants/endpoints.js";
|
||||
import createPersistedState from "vuex-persistedstate";
|
||||
import axios from "axios";
|
||||
import globalMethods from "@/global-methods";
|
||||
import router from "@/router";
|
||||
|
||||
export default createStore({
|
||||
plugins: [
|
||||
|
|
@ -27,17 +25,17 @@ export default createStore({
|
|||
mutations: {
|
||||
updateYear(state, data) {
|
||||
state.year = data.year;
|
||||
state.makes = data.makes;
|
||||
state.makes = data.makes.data;
|
||||
state.slideTransition = "slide";
|
||||
},
|
||||
updateMake(state, data) {
|
||||
state.make = data.make;
|
||||
state.models = data.models.data.Result;
|
||||
state.models = data.models.data;
|
||||
state.slideTransition = "slide";
|
||||
},
|
||||
updateModel(state, data) {
|
||||
state.model = data.model;
|
||||
state.styles = data.styles.data.Result;
|
||||
state.styles = data.styles.data;
|
||||
state.slideTransition = "slide";
|
||||
},
|
||||
updateStyle(state, data) {
|
||||
|
|
@ -55,50 +53,60 @@ export default createStore({
|
|||
},
|
||||
},
|
||||
actions: {
|
||||
async selectYear(context, year) {
|
||||
let makes = [];
|
||||
await globalMethods
|
||||
.callHttpClient({
|
||||
method: "GET",
|
||||
endpoint: `https://mockey.qa.sagaws.net/service/makes/year=${year}`,
|
||||
payload: {},
|
||||
})
|
||||
.then(function (response) {
|
||||
makes = response.data.Result;
|
||||
getYears(){
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetYears.method,
|
||||
endpoint: endpoints.GetYears.url,
|
||||
payload:{}
|
||||
});
|
||||
context.commit("updateYear", { year, makes });
|
||||
router.push(`/select-make?year=${year}`);
|
||||
},
|
||||
async selectMake({ commit, state }, make) {
|
||||
const models = await axios.get(
|
||||
`https://mockey.qa.sagaws.net/service/models/year=${state.year}/make=${make}`
|
||||
);
|
||||
commit("updateMake", { make, models });
|
||||
router.push(`/select-model?year=${state.year}&make=${make}`);
|
||||
},
|
||||
async selectModel({ commit, state }, model) {
|
||||
const styles = await axios.get(
|
||||
`https://mockey.qa.sagaws.net/service/styles/year=${state.year}/make=${state.make}/model=${model}`
|
||||
);
|
||||
commit("updateModel", { model, styles });
|
||||
router.push(
|
||||
`/select-style?year=${state.year}&make=${state.make}&model=${model}`
|
||||
);
|
||||
},
|
||||
selectStyle({ commit, state }, style) {
|
||||
commit("updateStyle", { style });
|
||||
router.push(
|
||||
`/damage?year=${state.year}&make=${state.make}&model=${state.model}&style=${style}`
|
||||
);
|
||||
},
|
||||
getRouteInfo(context, { pageName }) {
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetRouteInfoEndpoint.method,
|
||||
endpoint: endpoints.GetRouteInfoEndpoint.url,
|
||||
payload: {
|
||||
pageName: pageName,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
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: {
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,61 +1,41 @@
|
|||
.vehicle-select-attributes {
|
||||
height: 100vh;
|
||||
.select-car {
|
||||
height: calc(100vh - 1rem);
|
||||
|
||||
.select-car-form {
|
||||
background: $white;
|
||||
height: 100%;
|
||||
|
||||
form {
|
||||
height: calc(100% - 230px);
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.car_list, .current_car_info-text, .needed_car_info-text {
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
transition: transform .3s;
|
||||
}
|
||||
}
|
||||
|
||||
.current_car_info {
|
||||
position: relative;
|
||||
min-height: 2.5rem;
|
||||
|
||||
.current_car_info-text {
|
||||
position: absolute;
|
||||
}
|
||||
.car_list {
|
||||
// Height will be determined by overall height of content above list
|
||||
height: calc(100% - 100px);
|
||||
width: calc(100% - 1rem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Animations
|
||||
.slide-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(30vw);
|
||||
opacity: 0;
|
||||
transform: translateX(30vw);
|
||||
}
|
||||
.slide-enter-active, .slide-leave-active {
|
||||
transition: all .4s;
|
||||
transition: all .4s;
|
||||
}
|
||||
.slide-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-30vw);
|
||||
opacity: 0;
|
||||
transform: translateX(-30vw);
|
||||
}
|
||||
|
||||
.slide_reverse-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(-30vw);
|
||||
opacity: 0;
|
||||
transform: translateX(-30vw);
|
||||
}
|
||||
.slide_reverse-enter-active, .slide_reverse-leave-active {
|
||||
transition: all .4s;
|
||||
transition: all .4s;
|
||||
}
|
||||
.slide_reverse-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(30vw);
|
||||
opacity: 0;
|
||||
transform: translateX(30vw);
|
||||
}
|
||||
|
||||
.fade-enter-from, .fade-leave-to {
|
||||
opacity: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: all .5s ease;
|
||||
}
|
||||
transition: all .5s ease;
|
||||
}
|
||||
|
|
@ -14,12 +14,12 @@
|
|||
export default {
|
||||
name: "buttonPrimary",
|
||||
props: {
|
||||
buttonText: String
|
||||
buttonText: String,
|
||||
isDisabled: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isDisabled: false,
|
||||
isLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
|
|
|||
16
src/uxComponents/header/header.spec.js
Normal file
16
src/uxComponents/header/header.spec.js
Normal file
|
|
@ -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");
|
||||
})
|
||||
});
|
||||
16
src/uxComponents/header/header.vue
Normal file
16
src/uxComponents/header/header.vue
Normal file
|
|
@ -0,0 +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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Header",
|
||||
props: {
|
||||
text: String
|
||||
}
|
||||
};
|
||||
</script>
|
||||
23
src/uxComponents/radio/radio.spec.js
Normal file
23
src/uxComponents/radio/radio.spec.js
Normal file
|
|
@ -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'
|
||||
});
|
||||
})
|
||||
})
|
||||
39
src/uxComponents/radio/radio.vue
Normal file
39
src/uxComponents/radio/radio.vue
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<div>
|
||||
<input
|
||||
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' : '']"
|
||||
>
|
||||
<span>{{ text }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "radio",
|
||||
props: [
|
||||
"value",
|
||||
"text"
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
showLoader() {
|
||||
this.isLoading = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
Loading…
Reference in a new issue