| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- /* eslint-env jest */
- import Vue from 'vue'
- import registration from '@/ui-refactor/views/signup/components/welcomePackRegistration'
- import { getLanguages } from '@/api/setting'
- import request from '@/utils/request'
- jest.mock('@/api/setting', () => ({ getLanguages: jest.fn() }))
- jest.mock('@/utils/usersInfo', () => ({ userName: () => null, userEmail: () => null }))
- jest.mock('@/utils/request', () => jest.fn())
- function instance() {
- const vm = registration.data()
- vm.$message = jest.fn()
- vm.$message.error = jest.fn()
- vm.$t = key => key
- vm.$router = { push: jest.fn() }
- Object.keys(registration.methods).forEach(key => {
- vm[key] = registration.methods[key].bind(vm)
- })
- return vm
- }
- async function settle() {
- await Promise.resolve()
- await Promise.resolve()
- }
- describe('Signup welcome-pack compatibility', () => {
- beforeAll(() => jest.spyOn(window.location, 'assign').mockImplementation(() => {}))
- afterAll(() => window.location.assign.mockRestore())
- beforeEach(() => {
- jest.resetAllMocks()
- jest.useFakeTimers()
- })
- afterEach(() => {
- jest.clearAllTimers()
- jest.useRealTimers()
- })
- it.each([
- [{ ref: 'test-inviter' }, 'test-inviter'],
- [{ ref: ' test-inviter ' }, 'test-inviter'],
- [{}, ''],
- [{ ref: '' }, ''],
- [{ ref: ' ' }, ''],
- [{ ref: ['first', 'second'] }, '']
- ])('defaults both network IDs from the invitation query %j without making requests', (query, expected) => {
- const vm = new Vue({
- mixins: [registration],
- beforeCreate() {
- this.$route = { query }
- }
- })
- expect(vm.form.recUserName).toBe(expected)
- expect(vm.form.conUserName).toBe(expected)
- vm.form.recUserName = 'edited-referrer'
- vm.form.conUserName = 'edited-actual-referrer'
- expect(vm.form.recUserName).toBe('edited-referrer')
- expect(vm.form.conUserName).toBe('edited-actual-referrer')
- expect(request).not.toHaveBeenCalled()
- vm.$destroy()
- })
- it.each([
- ['', 'actual-referrer', 'Please enter the referrer ID.'],
- [' ', 'actual-referrer', 'Please enter the referrer ID.'],
- ['referrer', '', 'Please enter the actual referrer ID.'],
- ['referrer', ' ', 'Please enter the actual referrer ID.']
- ])('requires both network IDs before creating an order: %j / %j', (referrer, actualReferrer, message) => {
- const vm = instance()
- Object.assign(vm.form, { decLv: 'level', decUserName: 'center', recUserName: referrer, conUserName: actualReferrer })
- vm.isDec = '0'
- vm.draft = { draftId: 'test-draft', accessToken: 'test-only-guest-token' }
- vm.multipleSelection = [{ ID: 'goods', goodsNum: 1, MARKET_PRICE: 120 }]
- request.mockResolvedValue({ data: { accessCode: 'test-access-code', reference: 'test-reference' }})
- vm.onSubmit()
- expect(request).not.toHaveBeenCalled()
- expect(vm.submitButtonStat).toBe(false)
- expect(vm.$message.error).toHaveBeenCalledWith(message)
- })
- it('queries the guest referrer and resets the previous actual referrer', async() => {
- const vm = instance()
- vm.form.recUserName = 'test-referrer'
- vm.form.conUserName = 'previous-referrer'
- vm.form.autoPlace = 'previous-placement'
- vm.conRealName = 'Previous name'
- request.mockResolvedValue({ data: { REAL_NAME: 'Test referrer' }})
- vm.handleChkRecUser()
- expect(request).toHaveBeenCalledWith({
- url: '/v1/user/guest-full-info', method: 'get', params: { userName: 'test-referrer' }
- })
- expect(vm.form.conUserName).toBe('')
- expect(vm.form.autoPlace).toBe('')
- expect(vm.conRealName).toBe('-')
- expect(vm.loading).toBe(true)
- await settle()
- expect(vm.recRealName).toBe('Test referrer')
- expect(vm.loading).toBe(false)
- })
- it('queries the guest actual referrer with the existing network parameters', async() => {
- const vm = instance()
- vm.form.recUserName = 'test-referrer'
- vm.form.conUserName = 'test-actual-referrer'
- request.mockResolvedValue({ data: { REAL_NAME: 'Test actual referrer' }})
- vm.handleChkRecommenderActualName()
- expect(request).toHaveBeenCalledWith({
- url: '/v1/user/guest-inspect-network', method: 'get',
- params: { recommenderName: 'test-referrer', recommenderActualName: 'test-actual-referrer' }
- })
- expect(vm.loading).toBe(true)
- await settle()
- expect(vm.conRealName).toBe('Test actual referrer')
- expect(vm.loading).toBe(false)
- })
- it.each([
- ['handleChkRecUser', 'recRealName'],
- ['handleChkRecommenderActualName', 'conRealName']
- ])('clears the name and loading state when %s fails', async(method, nameField) => {
- const vm = instance()
- vm.form.recUserName = 'test-referrer'
- vm.form.conUserName = 'test-actual-referrer'
- vm[nameField] = 'Previous name'
- request.mockRejectedValue(new Error('Test query failure'))
- vm[method]()
- await settle()
- expect(vm[nameField]).toBe('-')
- expect(vm.loading).toBe(false)
- })
- it('does not query guest network information for empty referrer IDs', () => {
- const vm = instance()
- vm.handleChkRecUser()
- vm.handleChkRecommenderActualName()
- expect(request).not.toHaveBeenCalled()
- expect(vm.loading).toBe(false)
- })
- it('initializes with fixed country and language options without requesting lists', () => {
- const dispatch = jest.fn(() => Promise.resolve())
- const vm = new Vue({
- mixins: [registration],
- beforeCreate() {
- this.$store = { dispatch, getters: {}}
- }
- })
- expect(vm.countriesList).toEqual([
- { ID: '620699181539139625', NAME: 'Nigeria', DEFAULT_LANGUAGE_ID: '620713695651307520' }
- ])
- expect(vm.languageList).toEqual([
- { ID: '620713695718416384', NAME: '中文' },
- { ID: '620713695651307520', NAME: 'English' }
- ])
- expect(vm.form.countryId).toBe('')
- expect(dispatch).not.toHaveBeenCalled()
- expect(getLanguages).not.toHaveBeenCalled()
- expect(request).not.toHaveBeenCalled()
- vm.$destroy()
- })
- it('selects the country default language and automatically loads the guest order', async() => {
- const vm = instance()
- vm.form.countryId = '620699181539139625'
- vm.form.languageId = '620713695718416384'
- request.mockResolvedValue({ data: {
- draft: { draftId: 'test-draft', accessToken: 'test-only-token' },
- allGoods: [], region: [], decLevel: [], payList: {}
- }})
- vm.countriesChange()
- expect(vm.form.languageId).toBe('620713695651307520')
- expect(request).toHaveBeenCalledTimes(1)
- expect(request).toHaveBeenCalledWith({
- url: '/v1/user/guest-dec', method: 'get', params: { countryId: '620699181539139625' }
- })
- await settle()
- expect(vm.draft.draftId).toBe('test-draft')
- })
- it('loads guest identity, member ID, currency and payment methods from the selected country', async() => {
- const vm = instance()
- vm.form.countryId = 'country'
- const draft = {
- draftId: '90071992547409931234', accessToken: 'test-only-guest-token',
- insertUserName: 'test-guest', currency: 'NGN', expiresAt: 2000000000
- }
- const payList = { pay_stack: { label: 'pay_stack', name: 'Paystack' }}
- request.mockResolvedValue({ data: { draft, allGoods: [], region: [], decLevel: [], payList }})
- vm.fetchWelcomePack()
- expect(request).toHaveBeenCalledWith({
- url: '/v1/user/guest-dec', method: 'get', params: { countryId: 'country' }
- })
- await settle()
- jest.runOnlyPendingTimers()
- expect(vm.draft).toEqual(draft)
- expect(vm.form.insertUserName).toBe('test-guest')
- expect(vm.currencyUnitCode).toBe('NGN')
- expect(vm.payList).toEqual(payList)
- expect(vm.form.payType).toBe('pay_stack')
- expect(vm.userBalance).toEqual({ cash: 0 })
- expect(vm.loading).toBe(false)
- })
- it('clears the previous identity when reloading and keeps it cleared if the GET fails', async() => {
- const vm = instance()
- vm.draft = { draftId: 'old-draft', accessToken: 'test-only-old-token' }
- vm.form.insertUserName = 'old-guest'
- request.mockRejectedValue(new Error('Test load failure'))
- vm.countriesChange()
- expect(vm.draft).toEqual({})
- expect(vm.form.insertUserName).toBe('')
- await settle()
- expect(vm.loading).toBe(false)
- expect(vm.$message.error).toHaveBeenCalledWith('Test load failure')
- })
- it('ignores a delayed guest response for a previously selected country', async() => {
- const vm = instance()
- let resolvePrevious
- request.mockReturnValueOnce(new Promise(resolve => { resolvePrevious = resolve }))
- const draft = { draftId: 'current-draft', accessToken: 'test-only-current-token', insertUserName: 'current-guest' }
- request.mockResolvedValueOnce({ data: {
- draft, allGoods: [], region: [], decLevel: [],
- sellType: [{ sell_type: [{ label: 'pay_stack', name: 'Paystack' }] }]
- }})
- vm.form.countryId = 'previous'
- vm.countriesChange()
- vm.form.countryId = 'current'
- vm.countriesChange()
- await settle()
- resolvePrevious({ data: { draft: { draftId: 'previous-draft' }}})
- await settle()
- expect(vm.draft).toEqual(draft)
- expect(vm.form.insertUserName).toBe('current-guest')
- expect(vm.form.payType).toBe('pay_stack')
- })
- it('uses market price, quantity, BV and inclusive tax instead of the sales price', () => {
- const vm = instance()
- vm.tableData = [{ ID: 'goods', SELL_PRICE: 100, MARKET_PRICE: 120, PRICE_PV: 10, TAX_RATE: 10 }]
- vm.storeNums = [2]
- vm.handleSelectionChange(vm.tableData.slice())
- expect([vm.sellPriceSum, vm.pricePvSum, vm.taxSum]).toEqual(['240.00', '20.00', '21.82'])
- vm.handleSelectionChange([])
- expect([vm.sellPriceSum, vm.pricePvSum, vm.taxSum]).toEqual([0, 0, 0])
- })
- it('keeps the level, reporting center, product and cash balance guards', () => {
- const vm = instance()
- vm.onSubmit()
- vm.form.decLv = 'level'
- vm.isDec = '0'
- // 页面已有默认中心编号,此处显式清空,独立验证必填拦截。
- vm.form.decUserName = ''
- vm.onSubmit()
- vm.form.decUserName = 'center'
- vm.form.recUserName = 'test-referrer'
- vm.form.conUserName = 'test-actual-referrer'
- vm.onSubmit()
- vm.multipleSelection = [{ ID: 'goods', goodsNum: 2, MARKET_PRICE: 120 }]
- vm.form.payType = 'cash'
- vm.userBalance.cash = 1
- vm.onSubmit()
- expect(request).not.toHaveBeenCalled()
- expect(vm.$message.mock.calls.map(call => call[0].message)).toEqual([
- 'profile.selectLevel', 'shop.declarationCenterNumberTips', 'shop.balanceNotAllow'
- ])
- expect(vm.$message.error).toHaveBeenCalledWith('shop.chooseTips')
- })
- it.each([
- ['pay_stack', true],
- ['paystack', false]
- ])('preserves order fields and opens the existing payment dialog for %s', async(payType, wrapped) => {
- const vm = instance()
- vm.draft = { draftId: '90071992547409931234', accessToken: 'test-only-guest-token' }
- Object.assign(vm.form, {
- decLv: 'level', decUserName: 'center', countryId: 'country', languageId: 'language',
- recUserName: 'edited-referrer', conUserName: 'edited-actual-referrer',
- areaSelected: ['province', 'city', 'county'], openBank: 'bank', bankNo: 'account',
- bankAddress: 'account name', payType, password: 'test-only', payPassword: 'test-only'
- })
- vm.multipleSelection = [{ ID: 'goods', goodsNum: 2, MARKET_PRICE: 120 }]
- const order = {
- orderSn: 'test-order', amount: 873400, currency: 'NGN', reference: 'test-reference',
- authorizationUrl: 'https://checkout.paystack.com/test-checkout', accessCode: 'test-checkout'
- }
- request.mockResolvedValue(wrapped ? { data: order } : order)
- vm.onSubmit()
- expect(request).toHaveBeenCalledWith({
- url: '/v1/user/guest-dec', method: 'post', data: expect.objectContaining({
- draftId: '90071992547409931234', accessToken: 'test-only-guest-token',
- countryId: 'country', languageId: 'language', province: 'province', city: 'city', county: 'county',
- openBank: 'bank', bankNo: 'account', bankAddress: 'account name',
- recUserName: 'edited-referrer', conUserName: 'edited-actual-referrer',
- goodsId: ['goods'], goodsNum: [2], decType: 'normal', decWay: '2', location: 1, payType
- })
- })
- expect(request.mock.calls[0][0].data).not.toHaveProperty('way')
- expect(request.mock.calls[0][0].data).not.toHaveProperty('draft')
- await settle()
- expect(vm.submitButtonStat).toBe(false)
- expect(vm.visible).toBe(true)
- expect(vm.paymentOrder).toEqual(order)
- expect(vm.paymentOrder.amount).toBe(873400)
- expect(vm.$message).not.toHaveBeenCalled()
- jest.advanceTimersByTime(6000)
- expect(vm.$router.push).not.toHaveBeenCalled()
- expect(window.location.assign).not.toHaveBeenCalled()
- })
- it('does not submit a guest order without both temporary identifiers', () => {
- const vm = instance()
- vm.form.decLv = 'level'
- vm.form.recUserName = 'test-referrer'
- vm.form.conUserName = 'test-actual-referrer'
- vm.form.payType = 'pay_stack'
- vm.multipleSelection = [{ ID: 'goods', goodsNum: 1, MARKET_PRICE: 120 }]
- vm.onSubmit()
- vm.draft = { draftId: 'test-draft' }
- vm.onSubmit()
- vm.draft = { accessToken: 'test-only-guest-token' }
- vm.onSubmit()
- expect(request).not.toHaveBeenCalled()
- expect(vm.$message.error).toHaveBeenCalledTimes(3)
- expect(vm.submitButtonStat).toBe(false)
- })
- it('clears the submit loading state after a guest order failure', async() => {
- const vm = instance()
- vm.draft = { draftId: 'test-draft', accessToken: 'test-only-guest-token' }
- vm.form.decLv = 'level'
- vm.form.recUserName = 'test-referrer'
- vm.form.conUserName = 'test-actual-referrer'
- vm.form.payType = 'pay_stack'
- vm.multipleSelection = [{ ID: 'goods', goodsNum: 1, MARKET_PRICE: 120 }]
- request.mockRejectedValue('Test submit failure')
- vm.onSubmit()
- expect(vm.submitButtonStat).toBe(true)
- await settle()
- expect(vm.submitButtonStat).toBe(false)
- expect(vm.$message).toHaveBeenCalledWith({ message: 'Test submit failure', type: 'error' })
- })
- it.each([
- {},
- { reference: 'test-reference' },
- { accessCode: 'test-access-code' }
- ])('does not open checkout when the transaction identifiers are incomplete: %s', async(order) => {
- const vm = instance()
- vm.draft = { draftId: 'test-draft', accessToken: 'test-only-guest-token' }
- vm.form.decLv = 'level'
- vm.form.recUserName = 'test-referrer'
- vm.form.conUserName = 'test-actual-referrer'
- vm.form.payType = 'pay_stack'
- vm.multipleSelection = [{ ID: 'goods', goodsNum: 1, MARKET_PRICE: 120 }]
- request.mockResolvedValue({ data: order })
- vm.onSubmit()
- await settle()
- expect(vm.submitButtonStat).toBe(false)
- expect(window.location.assign).not.toHaveBeenCalled()
- expect(vm.$router.push).not.toHaveBeenCalled()
- expect(vm.$message).toHaveBeenCalledWith({ message: expect.any(String), type: 'error' })
- })
- it('refreshes payment details on every continuation using the current form and prevents concurrent requests', async() => {
- const vm = instance()
- vm.draft = { draftId: 'test-draft', accessToken: 'test-only-guest-token' }
- Object.assign(vm.form, {
- decLv: 'level', recUserName: 'test-referrer', conUserName: 'test-actual-referrer',
- payType: 'pay_stack', email: 'first@example.invalid'
- })
- vm.multipleSelection = [{ ID: 'goods', goodsNum: 1, MARKET_PRICE: 120 }]
- vm.paymentOrder = { orderSn: 'test-order', accessCode: 'test-access-code', reference: 'test-reference' }
- const firstOrder = { accessCode: 'first-access-code', reference: 'first-reference', amount: 120, currency: 'NGN' }
- const secondOrder = { accessCode: 'second-access-code', reference: 'second-reference', amount: 240, currency: 'NGN' }
- request.mockResolvedValueOnce({ data: firstOrder }).mockResolvedValueOnce({ data: secondOrder })
- vm.visible = true
- vm.handleClose()
- expect(vm.visible).toBe(false)
- vm.onSubmit()
- expect(vm.visible).toBe(false)
- expect(vm.submitButtonStat).toBe(true)
- vm.onSubmit()
- expect(request).toHaveBeenCalledTimes(1)
- await settle()
- expect(vm.visible).toBe(true)
- expect(vm.paymentOrder).toEqual(firstOrder)
- expect(vm.submitButtonStat).toBe(false)
- vm.handleClose()
- vm.form.email = 'updated@example.invalid'
- vm.multipleSelection[0].goodsNum = 2
- vm.onSubmit()
- expect(request).toHaveBeenCalledTimes(2)
- expect(request).toHaveBeenLastCalledWith({
- url: '/v1/user/guest-dec', method: 'post', data: expect.objectContaining({
- draftId: 'test-draft', accessToken: 'test-only-guest-token',
- email: 'updated@example.invalid', goodsId: ['goods'], goodsNum: [2]
- })
- })
- expect(vm.visible).toBe(false)
- await settle()
- expect(vm.visible).toBe(true)
- expect(vm.paymentOrder).toEqual(secondOrder)
- expect(vm.submitButtonStat).toBe(false)
- expect(window.location.assign).not.toHaveBeenCalled()
- expect(vm.$router.push).not.toHaveBeenCalled()
- })
- it.each([false, true])('does not reopen cached payment after a failed or incomplete refresh: %s', async(incomplete) => {
- const vm = instance()
- vm.draft = { draftId: 'test-draft', accessToken: 'test-only-guest-token' }
- Object.assign(vm.form, { decLv: 'level', recUserName: 'test-referrer', conUserName: 'test-actual-referrer', payType: 'pay_stack' })
- vm.multipleSelection = [{ ID: 'goods', goodsNum: 1, MARKET_PRICE: 120 }]
- vm.paymentOrder = { accessCode: 'old-access-code', reference: 'old-reference' }
- if (incomplete) request.mockResolvedValue({ data: { reference: 'new-reference' }})
- else request.mockRejectedValue(new Error('Unable to refresh payment.'))
- vm.onSubmit()
- expect(request).toHaveBeenCalledTimes(1)
- await settle()
- expect(vm.visible).toBe(false)
- expect(vm.submitButtonStat).toBe(false)
- expect(vm.$message).toHaveBeenCalledWith({
- message: incomplete ? 'Payment details are missing. Please contact customer service.' : 'Unable to refresh payment.',
- type: 'error'
- })
- })
- it('validates the edited form before requesting continued payment', () => {
- const vm = instance()
- vm.paymentOrder = { accessCode: 'old-access-code', reference: 'old-reference' }
- vm.onSubmit()
- expect(request).not.toHaveBeenCalled()
- expect(vm.visible).toBe(false)
- expect(vm.$message).toHaveBeenCalledWith({ message: 'profile.selectLevel', type: 'error' })
- })
- it('stays on signup after the payment callback and prevents another submission', () => {
- const vm = instance()
- vm.paymentOrder = { accessCode: 'test-access-code', reference: 'test-reference' }
- vm.visible = true
- vm.processPayment({ reference: 'test-reference' })
- expect(vm.visible).toBe(false)
- expect(vm.paymentComplete).toBe(true)
- expect(vm.$message).toHaveBeenCalledWith({
- message: 'Payment submitted. Please wait for order confirmation.', type: 'success'
- })
- vm.onSubmit()
- jest.advanceTimersByTime(6000)
- expect(request).not.toHaveBeenCalled()
- expect(window.location.assign).not.toHaveBeenCalled()
- expect(vm.$router.push).not.toHaveBeenCalled()
- })
- it.each([undefined, { reference: 'different-reference' }])('rejects a callback for a different payment: %s', response => {
- const vm = instance()
- vm.paymentOrder = { reference: 'test-reference' }
- vm.processPayment(response)
- expect(vm.paymentComplete).toBe(false)
- expect(vm.$message.error).toHaveBeenCalledWith('Payment reference does not match the current order.')
- expect(vm.$router.push).not.toHaveBeenCalled()
- })
- })
|