juice-shop
162 строки · 8.1 Кб
1/*
2* Copyright (c) 2014-2024 Bjoern Kimminich & the OWASP Juice Shop contributors.
3* SPDX-License-Identifier: MIT
4*/
5
6import { TranslateModule } from '@ngx-translate/core'7import { MatDividerModule } from '@angular/material/divider'8import { HttpClientTestingModule } from '@angular/common/http/testing'9import { type ComponentFixture, fakeAsync, TestBed, waitForAsync } from '@angular/core/testing'10import { RouterTestingModule } from '@angular/router/testing'11import { MatGridListModule } from '@angular/material/grid-list'12import { MatCardModule } from '@angular/material/card'13import { BrowserAnimationsModule } from '@angular/platform-browser/animations'14import { MatTableModule } from '@angular/material/table'15import { MatPaginatorModule } from '@angular/material/paginator'16import { MatDialogModule } from '@angular/material/dialog'17import { of, throwError } from 'rxjs'18import { OrderCompletionComponent } from './order-completion.component'19import { TrackOrderService } from '../Services/track-order.service'20import { ActivatedRoute, convertToParamMap } from '@angular/router'21import { MatIconModule } from '@angular/material/icon'22import { BasketService } from '../Services/basket.service'23import { MatTooltipModule } from '@angular/material/tooltip'24import { AddressService } from '../Services/address.service'25import { ConfigurationService } from '../Services/configuration.service'26
27export class MockActivatedRoute {28public paramMap = of(convertToParamMap({29id: 'ad9b-96017e7cb1ae7bf9'30}))31}
32
33describe('OrderCompletionComponent', () => {34let component: OrderCompletionComponent35let fixture: ComponentFixture<OrderCompletionComponent>36let trackOrderService: any37let activatedRoute: any38let basketService: any39let addressService: any40let configurationService: any41
42beforeEach(waitForAsync(() => {43configurationService = jasmine.createSpyObj('ConfigurationService', ['getApplicationConfiguration'])44configurationService.getApplicationConfiguration.and.returnValue(of({}))45trackOrderService = jasmine.createSpyObj('TrackOrderService', ['find'])46trackOrderService.find.and.returnValue(of({ data: [{ products: [] }] }))47activatedRoute = new MockActivatedRoute()48addressService = jasmine.createSpyObj('AddressService', ['getById'])49addressService.getById.and.returnValue(of([]))50
51TestBed.configureTestingModule({52declarations: [OrderCompletionComponent],53imports: [54RouterTestingModule,55HttpClientTestingModule,56TranslateModule.forRoot(),57BrowserAnimationsModule,58MatTableModule,59MatPaginatorModule,60MatDialogModule,61MatDividerModule,62MatGridListModule,63MatCardModule,64MatIconModule,65MatTooltipModule
66],67providers: [68{ provide: TrackOrderService, useValue: trackOrderService },69{ provide: ActivatedRoute, useValue: activatedRoute },70{ provide: BasketService, useValue: basketService },71{ provide: ConfigurationService, useValue: configurationService },72{ provide: AddressService, useValue: addressService }73]74})75.compileComponents()76}))77
78beforeEach(() => {79fixture = TestBed.createComponent(OrderCompletionComponent)80component = fixture.componentInstance81component.ngOnInit()82fixture.detectChanges()83})84
85it('should create', () => {86expect(component).toBeTruthy()87})88
89it('should hold order details returned by backend API', () => {90trackOrderService.find.and.returnValue(of({ data: [{ totalPrice: 2.88, promotionalAmount: 10, deliveryPrice: 2, addressId: 1, paymentId: 1, products: [{ quantity: 1, name: 'Apple Juice (1000ml)', price: 1.99, total: 1.99, bonus: 0 }, { quantity: 1, name: 'Apple Pomace', price: 0.89, total: 0.89, bonus: 0 }], bonus: 0, eta: '5' }] }))91component.ngOnInit()92fixture.detectChanges()93expect(component.promotionalDiscount).toBe(10)94expect(component.deliveryPrice).toBe(2)95expect(component.orderDetails.addressId).toBe(1)96expect(component.orderDetails.paymentId).toBe(1)97expect(parseFloat((component.orderDetails.totalPrice).toFixed(2))).toBe(2.88)98expect(parseFloat((component.orderDetails.itemTotal).toFixed(2))).toBe(10.88)99expect(component.orderDetails.eta).toBe('5')100expect(component.orderDetails.bonus).toBe(0)101expect(component.orderDetails.products.length).toBe(2)102expect(component.orderDetails.products[0].name).toBe('Apple Juice (1000ml)')103expect(component.orderDetails.products[1].name).toBe('Apple Pomace')104})105
106it('should have bullet point list of products in tweet', () => {107trackOrderService.find.and.returnValue(of({ data: [{ products: [{ name: 'A' }, { name: 'B' }] }] }))108configurationService.getApplicationConfiguration.and.returnValue(of({ }))109component.ngOnInit()110expect(component.tweetText).toBe('I just purchased%0a- A%0a- B')111})112
113it('should truncate tweet text if it exceeds 140 characters', () => {114trackOrderService.find.and.returnValue(of({ data: [{ products: [{ name: 'AAAAAAAAAAAAAAAAAAAA' }, { name: 'BBBBBBBBBBBBBBBBBBBB' }, { name: 'CCCCCCCCCCCCCCCCCCCC' }, { name: 'DDDDDDDDDDDDDDDDDDDD' }, { name: 'EEEEEEEEEEEEEEEEEEEE' }, { name: 'FFFFFFFFFFFFFFFFFFFF' }] }] }))115configurationService.getApplicationConfiguration.and.returnValue(of({ }))116component.ngOnInit()117expect(component.tweetText).toBe('I just purchased%0a- AAAAAAAAAAAAAAAAAAAA%0a- BBBBBBBBBBBBBBBBBBBB%0a- CCCCCCCCCCCCCCCCCCCC%0a- DDDDDDDDDDDDDDDDDDDD%0a- EEEEEEEEEEEEEEEEEEE...')118})119
120it('should derive twitter handle from twitter URL if configured', () => {121trackOrderService.find.and.returnValue(of({ data: [{ products: [] }] }))122configurationService.getApplicationConfiguration.and.returnValue(of({ application: { social: { twitterUrl: 'https://twitter.com/bkimminich' } } }))123component.ngOnInit()124expect(component.tweetText).toBe('I just purchased%0afrom @bkimminich')125})126
127it('should append twitter handle to truncated tweet text', () => {128trackOrderService.find.and.returnValue(of({ data: [{ products: [{ name: 'AAAAAAAAAAAAAAAAAAAA' }, { name: 'BBBBBBBBBBBBBBBBBBBB' }, { name: 'CCCCCCCCCCCCCCCCCCCC' }, { name: 'DDDDDDDDDDDDDDDDDDDD' }, { name: 'EEEEEEEEEEEEEEEEEEEE' }, { name: 'FFFFFFFFFFFFFFFFFFFF' }] }] }))129configurationService.getApplicationConfiguration.and.returnValue(of({ application: { social: { twitterUrl: 'https://twitter.com/owasp_juiceshop' } } }))130component.ngOnInit()131expect(component.tweetText).toBe('I just purchased%0a- AAAAAAAAAAAAAAAAAAAA%0a- BBBBBBBBBBBBBBBBBBBB%0a- CCCCCCCCCCCCCCCCCCCC%0a- DDDDDDDDDDDDDDDDDDDD%0a- EEEEEEEEEEEEEEEEEEE...%0afrom @owasp_juiceshop')132})133
134it('should use configured URL as is if it is not a twitter URL', () => {135trackOrderService.find.and.returnValue(of({ data: [{ products: [] }] }))136configurationService.getApplicationConfiguration.and.returnValue(of({ application: { social: { twitterUrl: 'http://localhorst:42' } } }))137component.ngOnInit()138expect(component.tweetText).toBe('I just purchased%0afrom http://localhorst:42')139})140
141it('should use configured application name as a fallback for missing twitter URL', () => {142trackOrderService.find.and.returnValue(of({ data: [{ products: [] }] }))143configurationService.getApplicationConfiguration.and.returnValue(of({ application: { name: 'OWASP Juice Shop', social: { twitterUrl: null } } }))144component.ngOnInit()145expect(component.tweetText).toBe('I just purchased%0afrom OWASP Juice Shop')146})147
148it('should log error while getting application configuration from backend API directly to browser console', fakeAsync(() => {149trackOrderService.find.and.returnValue(of({ data: [{ products: [] }] }))150configurationService.getApplicationConfiguration.and.returnValue(throwError('Error'))151console.log = jasmine.createSpy('log')152component.ngOnInit()153expect(console.log).toHaveBeenCalledWith('Error')154}))155
156it('should log error while getting order details from backend API directly to browser console', fakeAsync(() => {157trackOrderService.find.and.returnValue(throwError('Error'))158console.log = jasmine.createSpy('log')159component.ngOnInit()160expect(console.log).toHaveBeenCalledWith('Error')161}))162})163