Ionic Storage v3 – Unit Tests | TypeError: is not a function


I have a StorageService wrapper for @ionic/storage-angular where I have a function that looks roughly like this:

import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage-angular';

  providedIn: 'root'
export class StorageService {
  constructor(public storage: Storage) {}

  async getData() {
    const data = [];
    await this.initStorage();

    return new Promise((resolve) => {
        .forEach((value, key) => {
          if (key.startsWith('data-')) {
              key: 'someKey,
        .then(() => resolve(data));

  // other functions here

I have a unit test that looks like this

import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { fakeAsync, flush, TestBed } from '@angular/core/testing';
import { StorageService } from './storage.service';
import { Storage } from '@ionic/storage-angular';

describe('StorageService', () => {
  let service: StorageService;
  let mockStorage: jasmine.SpyObj<Storage>;

  beforeEach(() => {
    mockStorage = jasmine.createSpyObj('Storage', ['get', 'set', 'remove', 'create']);

      schemas: [CUSTOM_ELEMENTS_SCHEMA],
      providers: [
        { provide: Storage, useValue: mockStorage },
    service = TestBed.inject(StorageService);

  describe('getData()', () => {
    it('should call StorageService.initStorage()', fakeAsync(() => {
      spyOn<any>(service, 'initStorage').and.stub();



  // other tests here

It fails with

Error: Uncaught (in promise): TypeError: is not a function
        TypeError: is not a function

Storage itself is supposed to be iterable yet jasmine doesn’t see it as such because of the way I mocked it, I assume.

The question is: how do I unit test this bit correctly? I don’t want to create a real storage instance for testing purposes, is there a way to define as iterable via mocks?


Answering my own questions again.

My goal was to both preserve my spy object to mock storage.get and storage.set and be able to test storage.forEach. That doesn’t seem to be possible. The answer above may suit those who only need to test storage.forEach.

I resorted to not using storage.forEach at all and instead I iterate through storage.keys like this:

async getData(): Promise<Array<{key: string, value}>> {
    await this.initStorage();

      .then(keys => Promise.all(keys
        .filter(key => key.startsWith('data-'))
        .map(async key => {
          const value = await;

          return {
            key: 'someKey',

This yields the same result and is much easier to test. I just needed to add the keys method to my existing spy like this:

mockStorage = jasmine.createSpyObj('Storage', ['get', 'set', 'remove', 'create', 'keys']);

and then mock the return value

mockStorage.keys.and.resolveTo(['different', 'storage', 'keys']);

It’s rather straightforward from there. Hope this helps someone in the future.

Answered By – Dana

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published