Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix sonarlint issues #102

Merged
merged 2 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:4200",
"webRoot": "${workspaceFolder}"
}
]
}
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"sonarlint.connectedMode.project": {
"connectionId": "plageoj",
"projectKey": "plageoj_fukagawa-coffee"
}
},
"simplecov-vscode.enabled": false
}
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"eslint-config-prettier": "^9.1.0",
"inquirer-autocomplete-prompt": "^3.0.1",
"jasmine-core": "~5.4.0",
"jasmine-marbles": "^0.9.2",
"jasmine-spec-reporter": "~7.0.0",
"karma": "~6.4.4",
"karma-chrome-launcher": "~3.2.0",
Expand Down
39 changes: 21 additions & 18 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,32 @@ import { MatIcon } from '@angular/material/icon';
import { MatToolbar } from '@angular/material/toolbar';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
standalone: true,
imports: [
MatToolbar,
MatIcon,
NgIf,
MatIconButton,
MatSidenavContainer,
MatSidenav,
MatNavList,
MatListItem,
RouterLink,
MatSidenavContent,
RouterOutlet,
],
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
standalone: true,
imports: [
MatToolbar,
MatIcon,
NgIf,
MatIconButton,
MatSidenavContainer,
MatSidenav,
MatNavList,
MatListItem,
RouterLink,
MatSidenavContent,
RouterOutlet,
],
})
export class AppComponent {
user: User | null = null;
siteName = environment.siteName;

constructor(private auth: Auth, private router: Router) {
constructor(
private readonly auth: Auth,
private readonly router: Router,
) {
onAuthStateChanged(this.auth, (user) => {
this.user = user;
});
Expand Down
26 changes: 9 additions & 17 deletions src/app/components/item-selector/item-selector.component.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
import { AsyncPipe, NgClass, NgFor, NgIf } from '@angular/common';
import { Component, EventEmitter, Output } from '@angular/core';
import { MatGridList, MatGridTile } from '@angular/material/grid-list';
import { MatIcon } from '@angular/material/icon';
import { Observable } from 'rxjs';
import { ItemService } from 'src/app/services/item.service';
import { Item } from 'src/models/item.model';
import { MatIcon } from '@angular/material/icon';
import { MatGridList, MatGridTile } from '@angular/material/grid-list';
import { NgIf, NgFor, NgClass, AsyncPipe } from '@angular/common';

@Component({
selector: 'app-item-selector',
templateUrl: './item-selector.component.html',
styleUrls: ['./item-selector.component.scss'],
standalone: true,
imports: [
NgIf,
MatGridList,
NgFor,
MatGridTile,
NgClass,
MatIcon,
AsyncPipe,
],
selector: 'app-item-selector',
templateUrl: './item-selector.component.html',
styleUrls: ['./item-selector.component.scss'],
standalone: true,
imports: [NgIf, MatGridList, NgFor, MatGridTile, NgClass, MatIcon, AsyncPipe],
})
export class ItemSelectorComponent {
columns = Math.floor(window.innerWidth / 170).toString();
items: Observable<Item[]>;

@Output() choose = new EventEmitter<Item>();

constructor(private is: ItemService) {
constructor(private readonly is: ItemService) {
this.items = this.is.list();
}

Expand Down
2 changes: 1 addition & 1 deletion src/app/customer/add-customer/add-customer.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { CustomerDialogData } from 'src/models/customer.model';
export class AddCustomerComponent {
constructor(
@Inject(MAT_DIALOG_DATA) public data: CustomerDialogData,
private cs: CustomerService,
private readonly cs: CustomerService,
) {
if (typeof data.customer.id === 'undefined') {
data.customer = {
Expand Down
44 changes: 25 additions & 19 deletions src/app/customer/associate-item/associate-item.component.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
import { CdkScrollable } from '@angular/cdk/scrolling';
import { Component } from '@angular/core';
import { MatDialogRef, MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose } from '@angular/material/dialog';
import { Item } from 'src/models/item.model';
import { MatIcon } from '@angular/material/icon';
import { MatButton } from '@angular/material/button';
import {
MatDialogActions,
MatDialogClose,
MatDialogContent,
MatDialogRef,
MatDialogTitle,
} from '@angular/material/dialog';
import { MatIcon } from '@angular/material/icon';
import { Item } from 'src/models/item.model';
import { ItemSelectorComponent } from '../../components/item-selector/item-selector.component';
import { CdkScrollable } from '@angular/cdk/scrolling';

@Component({
selector: 'app-associate-item',
templateUrl: './associate-item.component.html',
styleUrls: ['./associate-item.component.scss'],
standalone: true,
imports: [
MatDialogTitle,
CdkScrollable,
MatDialogContent,
ItemSelectorComponent,
MatDialogActions,
MatButton,
MatDialogClose,
MatIcon,
],
selector: 'app-associate-item',
templateUrl: './associate-item.component.html',
styleUrls: ['./associate-item.component.scss'],
standalone: true,
imports: [
MatDialogTitle,
CdkScrollable,
MatDialogContent,
ItemSelectorComponent,
MatDialogActions,
MatButton,
MatDialogClose,
MatIcon,
],
})
export class AssociateItemComponent {
constructor(private ref: MatDialogRef<AssociateItemComponent>) {}
constructor(private readonly ref: MatDialogRef<AssociateItemComponent>) {}

associateItem(item: Item) {
this.ref.close(item);
Expand Down
139 changes: 135 additions & 4 deletions src/app/customer/customer-detail/customer-detail.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,163 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { CustomerDetailComponent } from './customer-detail.component';
import { FirebaseTestingModule } from 'src/app/firebase-testing.module';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatButtonHarness } from '@angular/material/button/testing';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, convertToParamMap } from '@angular/router';
import { cold } from 'jasmine-marbles';
import { FirebaseTestingModule } from 'src/app/firebase-testing.module';
import { CustomerService } from 'src/app/services/customer.service';
import { ItemService } from 'src/app/services/item.service';
import { Customer } from 'src/models/customer.model';
import { Item } from 'src/models/item.model';
import { CustomerDetailComponent } from './customer-detail.component';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { of } from 'rxjs';
import { MatSnackBar } from '@angular/material/snack-bar';

describe('CustomerDetailComponent', () => {
let component: CustomerDetailComponent;
let fixture: ComponentFixture<CustomerDetailComponent>;
let loader: HarnessLoader;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [FirebaseTestingModule, CustomerDetailComponent],
imports: [
FirebaseTestingModule,
CustomerDetailComponent,
NoopAnimationsModule,
],
providers: [
{
provide: ActivatedRoute,
useValue: { snapshot: { paramMap: convertToParamMap({}) } },
useValue: {
snapshot: {
paramMap: convertToParamMap({
id: 'test-id',
}),
},
},
},
],
}).compileComponents();

const customerService = TestBed.inject(CustomerService);
spyOn(customerService, 'load').and.returnValue(
cold('c|', {
c: {
id: 'test-id',
name: 'Test Customer',
address: '123 Main Street',
items: {
test: true,
},
} as Customer,
}),
);

const itemService = TestBed.inject(ItemService);
spyOn(itemService, 'list').and.returnValue(
cold('i|', {
i: [
{
id: 'test',
name: 'Test Item',
} as Item,
],
}),
);
});

beforeEach(() => {
fixture = TestBed.createComponent(CustomerDetailComponent);
component = fixture.componentInstance;
loader = TestbedHarnessEnvironment.loader(fixture);
fixture.detectChanges();
});
Comment on lines 72 to 77
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

beforeEachフックが重複しています

同じdescribeブロック内に2つのbeforeEachフックが存在します。これはテストの予期しない動作を引き起こす可能性があります。一つに統合することをお勧めします。

以下の差分を適用してbeforeEachフックを統合してください:

- beforeEach(async () => {
+ beforeEach(async () => {
    await TestBed.configureTestingModule({
        // 既存の設定
    }).compileComponents();

    const customerService = TestBed.inject(CustomerService);
    // 既存のスパイ設定
    const itemService = TestBed.inject(ItemService);
    // 既存のスパイ設定

+   fixture = TestBed.createComponent(CustomerDetailComponent);
+   component = fixture.componentInstance;
+   loader = TestbedHarnessEnvironment.loader(fixture);
+   fixture.detectChanges();
 });
 
- beforeEach(() => {
-   fixture = TestBed.createComponent(CustomerDetailComponent);
-   component = fixture.componentInstance;
-   loader = TestbedHarnessEnvironment.loader(fixture);
-   fixture.detectChanges();
- });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
beforeEach(() => {
fixture = TestBed.createComponent(CustomerDetailComponent);
component = fixture.componentInstance;
loader = TestbedHarnessEnvironment.loader(fixture);
fixture.detectChanges();
});
beforeEach(async () => {
await TestBed.configureTestingModule({
// 既存の設定
}).compileComponents();
const customerService = TestBed.inject(CustomerService);
// 既存のスパイ設定
const itemService = TestBed.inject(ItemService);
// 既存のスパイ設定
fixture = TestBed.createComponent(CustomerDetailComponent);
component = fixture.componentInstance;
loader = TestbedHarnessEnvironment.loader(fixture);
fixture.detectChanges();
});
🧰 Tools
🪛 Biome

[error] 72-77: Disallow duplicate setup and teardown hooks.

Disallow beforeEach duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)


it('should create', () => {
expect(component).toBeTruthy();
});

it('associate item', async () => {
const dialogSpy = (
spyOn(TestBed.inject(MatDialog), 'open') as jasmine.Spy
).and.returnValue({
afterClosed: () =>
of({
id: 'test',
name: 'Test Item',
}),
});
const button = await loader.getHarness(
MatButtonHarness.with({ text: /品目を追加する/ }),
);
await button.click();

expect(dialogSpy).toHaveBeenCalled();
});

it('edit customer', async () => {
const dialogSpy = spyOn(
TestBed.inject(MatDialog),
'open',
).and.callThrough();
const button = await loader.getHarness(
MatButtonHarness.with({ text: /編集/ }),
);
await button.click();

expect(dialogSpy).not.toHaveBeenCalled();

component.customer = {
id: 'test-id',
name: 'Test Customer',
address: '123 Main Street',
items: {
test: true,
},
};

fixture.detectChanges();
await button.click();
expect(dialogSpy).toHaveBeenCalled();
});

it('delete customer', async () => {
const dialogSpy = (
spyOn(TestBed.inject(MatSnackBar), 'open') as jasmine.Spy
).and.returnValue({
afterDismissed: () => of({ dismissedByAction: false }),
});
const button = await loader.getHarness(
Comment on lines +128 to +133
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

変数名 'dialogSpy' が誤解を招く可能性があります

MatSnackBaropenメソッドをスパイしていますが、変数名がdialogSpyとなっており、ダイアログをスパイしているように見えます。snackBarSpyなど、より適切な名前に変更することをお勧めします。

以下の差分を適用してください:

- const dialogSpy = (
+ const snackBarSpy = (
    spyOn(TestBed.inject(MatSnackBar), 'open') as jasmine.Spy
).and.returnValue({
    afterDismissed: () => of({ dismissedByAction: false }),
});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const dialogSpy = (
spyOn(TestBed.inject(MatSnackBar), 'open') as jasmine.Spy
).and.returnValue({
afterDismissed: () => of({ dismissedByAction: false }),
});
const button = await loader.getHarness(
const snackBarSpy = (
spyOn(TestBed.inject(MatSnackBar), 'open') as jasmine.Spy
).and.returnValue({
afterDismissed: () => of({ dismissedByAction: false }),
});
const button = await loader.getHarness(

MatButtonHarness.with({ text: /削除/ }),
);
await button.click();
expect(dialogSpy).not.toHaveBeenCalled();
component.customer = {
id: 'test-id',
name: 'Test Customer',
address: '123 Main Street',
items: {
test: true,
},
};
fixture.detectChanges();
await button.click();
expect(dialogSpy).toHaveBeenCalled();
});

it('delete item', () => {
component.customer = {
id: 'test-id',
name: 'Test Customer',
address: '123 Main Street',
items: {
test: true,
},
};
component.deleteItem('test');
expect(component.customer?.items).toEqual({});
});
});
Loading