Ionic 4: Создание фиктивного хранилища

Я пытаюсь использовать Testbed в новом приложении Angular 7/Ionic 4, но не могу запустить какие-либо тесты, потому что мои компоненты зависят от собственного плагина Ionic, место хранения.

app.component.spec.ts

import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import {TestBed, async, fakeAsync, tick} from '@angular/core/testing';

import { Platform } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import {RouterTestingModule} from '@angular/router/testing';
import {Router} from '@angular/router';
import {Location} from '@angular/common'

import { LoginPage } from './pages/login/login.page';
import { routes } from "./app-routing.module";
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {StorageMock} from './testing/mocks/storage.mock';
import {IonicStorageModule} from '@ionic/storage';

describe('AppComponent', () => {

  let statusBarSpy, splashScreenSpy, platformReadySpy, platformSpy, storageSpy;
  let router: Router;
  let location: Location;
  let fixture;
  let comp: AppComponent;

  beforeEach(async(() => {
    statusBarSpy = jasmine.createSpyObj('StatusBar', ['styleDefault']);
    splashScreenSpy = jasmine.createSpyObj('SplashScreen', ['hide']);
    platformReadySpy = Promise.resolve();
    platformSpy = jasmine.createSpyObj('Platform', { ready: platformReadySpy });
    storageSpy = jasmine.createSpyObj('Storage', ['get', 'set', 'clear', 'remove', 'ready']);

    TestBed.configureTestingModule({
      declarations: [AppComponent],
      imports: [
        RouterTestingModule.withRoutes(routes),
        IonicStorageModule.forRoot(),
        HttpClientTestingModule,
      ],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
      providers: [
        { provide: StatusBar, useValue: statusBarSpy },
        { provide: SplashScreen, useValue: splashScreenSpy },
        { provide: Platform, useValue: platformSpy },
        { provide: Storage, useClass: StorageMock }
      ],
    }).compileComponents();

    router = TestBed.get(Router);
    location = TestBed.get(Location);
    fixture = TestBed.createComponent(AppComponent);
    comp = fixture.componentInstance;
    router.initialNavigation();
  }));

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  });

  it('should initialize the app', async () => {
    TestBed.createComponent(AppComponent);
    expect(platformSpy.ready).toHaveBeenCalled();
    await platformReadySpy;
    expect(statusBarSpy.styleDefault).toHaveBeenCalled();
    expect(splashScreenSpy.hide).toHaveBeenCalled();
  });

  it('navigates to "" redirects you to /login', fakeAsync(() => {
    router.navigate(['']);
    tick();
    expect(location.path()).toBe('/login')
  }));

  afterEach(() => {
    fixture.destroy();
    comp = null
  })
});

И создал свой собственный StorageMock:

import {Storage, StorageConfig} from '@ionic/storage';

export class StorageMock extends Storage {
  driver: string;
  vals: {};

  constructor(config: StorageConfig) {
    super({})
  }

  clear() {
    return new Promise<void>((res) => res())
  }

  ready() {
    return new Promise<LocalForage>((res) => res())
  }

  get(key: string) {
    return new Promise((res) => res(this.vals[key]))
  }

  set(key, val) {
    return new Promise((res) => {
      this.vals[key] = val;
      res()
    })
  }

  remove(key) {
    return new Promise((res) => {
      delete this.vals[key];
      res()
    })
  }
}

Однако, когда я запускаю свой тест, я все еще вижу:

Error: Can't resolve all parameters for Storage: (?).

Что мне не хватает?

используйте локальное хранилище, оно будет работать

ram12393 24.04.2019 07:03
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
8
1
3 325
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Сначала импортируйте хранилище:

import { Storage } from '@ionic/storage';

Создайте константу для макета:

 const storageIonicMock: any = {
     get: () => new Promise<any>((resolve, reject) => resolve('As2342fAfgsdr')),
     set: () => ...
    };

Настройте свою кровать TesBed

TestBed.configureTestingModule({
      imports: [],
      providers: [
        {
          provide: Storage,
          useValue: storageIonicMock
        }
      ]
    });

Плагин Ionic место хранения также работает в среде браузера.

Вам не нужно создавать макет, и вы можете напрямую импортировать, определять и внедрять его в свой компонент (если вы запускаете тест в среде браузера):

Первый импорт:

import { Storage } from '@ionic/storage';
import { MyComponent } from './my-component';

Объявите глобальную переменную компонента:

let component: MyComponent;

Затем и для каждого теста определите и внедрите хранилище в свой компонент:

beforeEach(() => {
    const storage = new Storage({         // Define Storage
      name: '__mydb',
      driverOrder: ['indexeddb', 'sqlite', 'websql']
    });
    component = new MyComponent(storage); // Inject Storage in your component
  }

Как писали другие, Хранилище работает в браузерах, поэтому мне не нужно было издеваться над ним для тестирования. Это сработало для меня (StorageWrapperService - это мой сервис, который зависит от хранилища Ionic):

import { TestBed } from '@angular/core/testing';

import { StorageWrapperService } from './storage-wrapper.service';
import { IonicStorageModule, Storage } from '@ionic/storage';

describe('StorageWrapperService', () => {
  let service: StorageWrapperService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        IonicStorageModule.forRoot({
          name: '__mydb',
          driverOrder: ['localstorage']
        })
      ],
    });
    service = TestBed.inject(StorageWrapperService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

});

Дополнительная информация:

localstorage не будет очищаться между тестами, поэтому, вероятно, вы захотите использовать что-то вроде этого:

describe('StorageWrapperService', () => {
  let service: StorageWrapperService;
  let storage: Storage;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        IonicStorageModule.forRoot({
          name: '__mydb',
          driverOrder: ['localstorage']
        })
      ]
    });
    service = TestBed.inject(StorageWrapperService);
    storage = TestBed.inject(Storage);
  });

...
});

И очистить хранилище в конце каждого теста:

  it('...', (done) => {
      storage.clear().then(() => done());
  });

Другие вопросы по теме