• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

juice-shop / juice-shop / 19995569076

06 Dec 2025 11:08PM UTC coverage: 86.117% (-0.04%) from 86.156%
19995569076

push

github

bkimminich
Merge remote-tracking branch 'origin/develop' into develop

1255 of 1676 branches covered (74.88%)

Branch coverage included in aggregate %.

313 of 319 new or added lines in 92 files covered. (98.12%)

26 existing lines in 7 files now uncovered.

5345 of 5988 relevant lines covered (89.26%)

40.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.23
/frontend/src/app/payment-method/payment-method.component.ts
1
/*
2
 * Copyright (c) 2014-2026 Bjoern Kimminich & the OWASP Juice Shop contributors.
3
 * SPDX-License-Identifier: MIT
4
 */
5

6
import { UntypedFormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'
7
import { Component, EventEmitter, Input, type OnInit, Output, inject } from '@angular/core'
8
import { PaymentService } from '../Services/payment.service'
9
import { MatTableDataSource, MatTable, MatColumnDef, MatHeaderCellDef, MatHeaderCell, MatCellDef, MatCell, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow } from '@angular/material/table'
10
import { library } from '@fortawesome/fontawesome-svg-core'
11
import { faPaperPlane } from '@fortawesome/free-solid-svg-icons'
12
import { faTrashAlt } from '@fortawesome/free-regular-svg-icons/'
13
import { TranslateService, TranslateModule } from '@ngx-translate/core'
14
import { SnackBarHelperService } from '../Services/snack-bar-helper.service'
15
import { MatInputModule } from '@angular/material/input'
16
import { MatFormFieldModule, MatLabel, MatError, MatHint } from '@angular/material/form-field'
17
import { MatExpansionPanel, MatExpansionPanelHeader, MatExpansionPanelTitle, MatExpansionPanelDescription } from '@angular/material/expansion'
18
import { MatIconButton, MatButtonModule } from '@angular/material/button'
19
import { MatRadioButton } from '@angular/material/radio'
20

21
import { MatIconModule } from '@angular/material/icon'
22

23
library.add(faPaperPlane, faTrashAlt)
1✔
24

25
@Component({
26
  selector: 'app-payment-method',
27
  templateUrl: './payment-method.component.html',
28
  styleUrls: ['./payment-method.component.scss'],
29
  imports: [MatTable, MatColumnDef, MatHeaderCellDef, MatHeaderCell, MatCellDef, MatCell, MatRadioButton, MatIconButton, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow, MatExpansionPanel, MatExpansionPanelHeader, MatExpansionPanelTitle, MatExpansionPanelDescription, MatFormFieldModule, MatLabel, TranslateModule, MatInputModule, FormsModule, ReactiveFormsModule, MatError, MatHint, MatButtonModule, MatIconModule]
30
})
31

32
export class PaymentMethodComponent implements OnInit {
1✔
33
  paymentService = inject(PaymentService)
37✔
34
  private readonly translate = inject(TranslateService)
37✔
35
  private readonly snackBarHelperService = inject(SnackBarHelperService)
37✔
36

37
  @Output() emitSelection = new EventEmitter()
37✔
38
  @Input() public allowDelete = false
37✔
39
  public displayedColumns = ['Number', 'Name', 'Expiry']
37✔
40
  public nameControl: UntypedFormControl = new UntypedFormControl('', [Validators.required])
37✔
41
  // eslint-disable-next-line no-loss-of-precision
42
  public numberControl: UntypedFormControl = new UntypedFormControl('', [Validators.required, Validators.min(1000000000000000), Validators.max(9999999999999999)])
37✔
43
  public monthControl: UntypedFormControl = new UntypedFormControl('', [Validators.required])
37✔
44
  public yearControl: UntypedFormControl = new UntypedFormControl('', [Validators.required])
37✔
45
  public confirmation: any
46
  public error: any
47
  public storedCards: any
48
  public card: any = {}
37✔
49
  public dataSource
50
  public readonly monthRange = Array.from(Array(12).keys()).map(i => i + 1)
444✔
51
  public readonly yearRange = Array.from(Array(20).keys()).map(i => i + 2080)
740✔
52
  public cardsExist = false
37✔
53
  public paymentId: any = undefined
37✔
54

55
  ngOnInit (): void {
56
    if (this.allowDelete) {
37✔
57
      this.displayedColumns.push('Remove')
1✔
58
    } else {
59
      this.displayedColumns.unshift('Selection')
36✔
60
    }
61
    this.load()
37✔
62
  }
63

64
  load () {
65
    this.paymentService.get().subscribe({
41✔
66
      next: (cards) => {
67
        this.cardsExist = cards.length
15✔
68
        this.storedCards = cards
15✔
69
        this.dataSource = new MatTableDataSource<Element>(this.storedCards)
15✔
70
      },
71
      error: (err) => { console.log(err) }
2✔
72
    })
73
  }
74

75
  save () {
76
    this.card.fullName = this.nameControl.value
2✔
77
    this.card.cardNum = this.numberControl.value
2✔
78
    this.card.expMonth = this.monthControl.value
2✔
79
    this.card.expYear = this.yearControl.value
2✔
80
    this.paymentService.save(this.card).subscribe({
2✔
81
      next: (savedCards) => {
82
        this.error = null
1✔
83
        this.translate.get('CREDIT_CARD_SAVED', { cardnumber: String(savedCards.cardNum).substring(String(savedCards.cardNum).length - 4) }).subscribe({
1✔
84
          next: (creditCardSaved) => {
85
            this.snackBarHelperService.open(creditCardSaved, 'confirmBar')
1✔
86
          },
87
          error: (translationId) => {
UNCOV
88
            this.snackBarHelperService.open(translationId, 'confirmBar')
×
89
          }
90
        })
91
        this.load()
1✔
92
        this.resetForm()
1✔
93
      },
94
      error: (err) => {
95
        this.snackBarHelperService.open(err.error?.error, 'errorBar')
1✔
96
        this.resetForm()
1✔
97
      }
98
    })
99
  }
100

101
  delete (id) {
102
    this.paymentService.del(id).subscribe({
×
103
      next: () => {
104
        this.load()
×
105
      },
UNCOV
106
      error: (err) => { console.log(err) }
×
107
    })
108
  }
109

110
  emitSelectionToParent (id: number) {
UNCOV
111
    this.emitSelection.emit(id)
×
112
  }
113

114
  resetForm () {
115
    this.nameControl.markAsUntouched()
1✔
116
    this.nameControl.markAsPristine()
1✔
117
    this.nameControl.setValue('')
1✔
118
    this.numberControl.markAsUntouched()
1✔
119
    this.numberControl.markAsPristine()
1✔
120
    this.numberControl.setValue('')
1✔
121
    this.monthControl.markAsUntouched()
1✔
122
    this.monthControl.markAsPristine()
1✔
123
    this.monthControl.setValue('')
1✔
124
    this.yearControl.markAsUntouched()
1✔
125
    this.yearControl.markAsPristine()
1✔
126
    this.yearControl.setValue('')
1✔
127
  }
128
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc