rxjs/operators#concatMapTo TypeScript Examples

The following examples show how to use rxjs/operators#concatMapTo. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: dia-backend-auth.service.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
updateUser$({ username }: { username: string }) {
    return defer(() => this.getAuthHeaders()).pipe(
      concatMap(headers =>
        this.httpClient.patch<UpdateUserResponse>(
          `${BASE_URL}/auth/users/me/`,
          { username },
          { headers }
        )
      ),
      concatMapTo(this.readUser$()),
      concatMap(response =>
        forkJoin([
          this.setUsername(response.username),
          this.setEmail(response.email),
          this.setRerferralCode(response.referral_code),
        ])
      )
    );
  }
Example #2
Source File: copy-clipboard.component.ts    From ionic-pwa-example-moment with MIT License 6 votes vote down vote up
copy() {
    return this.text$
      .pipe(
        tap(text => {
          const listener = (e: ClipboardEvent) => {
            e.clipboardData?.setData('text', text);
            e.preventDefault();
          };
          document.addEventListener('copy', listener, false);
          document.execCommand('copy');
          document.removeEventListener('copy', listener, false);
        }),
        concatMapTo(this.presentToast$),
        untilDestroyed(this)
      )
      .subscribe();
  }
Example #3
Source File: camera.service.ts    From ionic-pwa-example-moment with MIT License 6 votes vote down vote up
function revokePreviousImageUrl() {
  return (source$: Observable<string>) =>
    source$.pipe(
      startWith(undefined),
      pairwise(),
      tap(([previous]) => {
        if (previous) URL.revokeObjectURL(previous);
      }),
      concatMapTo(source$)
    );
}
Example #4
Source File: camera.service.ts    From ionic-pwa-example-moment with MIT License 6 votes vote down vote up
readonly stream$ = this.devices$.pipe(
    first(),
    concatMap(devices => this.getCurrentVideoMedia(devices)),
    tap(mediaStream => this._stream$.next(mediaStream)),
    concatMapTo(this._stream$),
    shareReplay({ bufferSize: 1, refCount: true }),
    isNonNullable(),
    finalizeLast(mediaStream => stopMediaStream(mediaStream)),
    shareReplay({ bufferSize: 1, refCount: true })
  );
Example #5
Source File: camera.service.ts    From ionic-pwa-example-moment with MIT License 6 votes vote down vote up
next$() {
    return this.stream$.pipe(
      first(),
      tap(mediaStream => mediaStream.getVideoTracks().forEach(t => t.stop())),
      concatMapTo(this.devices$),
      tap(() => this.currentVideoDeviceIndex++),
      concatMap(devices => this.getCurrentVideoMedia(devices)),
      tap(mediaStream => this._stream$.next(mediaStream))
    );
  }
Example #6
Source File: camera.service.ts    From ionic-pwa-example-moment with MIT License 6 votes vote down vote up
nextCamera$(videoElement: HTMLVideoElement) {
    return this.videoDevices$.pipe(
      first(),
      concatMap(devices =>
        iif(
          () => devices.length > 1,
          defer(async () => (videoElement.srcObject = null)).pipe(
            concatMapTo(this.videoStreamSelector.next$())
          )
        )
      )
    );
  }
Example #7
Source File: photo.page.ts    From ionic-pwa-example-moment with MIT License 6 votes vote down vote up
remove() {
    const action$ = this.currentMemontId$.pipe(
      first(),
      tap(() => (this.willBeDestroyed = true)),
      concatMap(id => this.momentRepository.remove$(id)),
      concatMapTo(defer(() => this.router.navigate(['..'])))
    );

    return this.dialogsService
      .presentConfirmation$({
        headerKey: 'deleteMoment',
        messageKey: 'message.deleteMoment',
      })
      .pipe(
        first(),
        concatMap(result => iif(() => result, action$)),
        untilDestroyed(this)
      )
      .subscribe();
  }
Example #8
Source File: home.page.ts    From ionic-pwa-example-moment with MIT License 6 votes vote down vote up
private readonly onboardIfNecessary$ = this.onboardingService.hasOnboarded$.pipe(
    switchMap(hasOnboarded =>
      iif(
        () => !hasOnboarded,
        this.translocoService
          .selectTranslateObject([])
          .pipe(concatMapTo(this.errorReportService.showUserAgreeDialog$))
      )
    ),
    concatMapTo(this.onboardingService.onboard$)
  );
Example #9
Source File: dia-backend-transaction-repository.service.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
private list$({ offset, limit }: { offset?: number; limit?: number }) {
    // eslint-disable-next-line @typescript-eslint/require-await
    return defer(async () => this._isFetching$.next(true)).pipe(
      concatMapTo(defer(() => this.authService.getAuthHeaders())),
      concatMap(headers => {
        let params = new HttpParams();

        if (offset !== undefined) {
          params = params.set('offset', `${offset}`);
        }
        if (limit !== undefined) {
          params = params.set('limit', `${limit}`);
        }

        return this.httpClient.get<PaginatedResponse<DiaBackendTransaction>>(
          `${BASE_URL}/api/v3/transactions/`,
          { headers, params }
        );
      }),
      tap(() => this._isFetching$.next(false))
    );
  }
Example #10
Source File: dia-backend-contact-repository.service.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
private list$({
    email,
    limit,
    offset,
  }: {
    email?: string;
    limit?: number;
    offset?: number;
  }) {
    return defer(async () => this._isFetching$.next(true)).pipe(
      concatMapTo(defer(() => this.authService.getAuthHeaders())),
      concatMap(headers => {
        let params = new HttpParams();

        if (offset !== undefined) {
          params = params.set('offset', `${offset}`);
        }
        if (limit !== undefined) {
          params = params.set('limit', `${limit}`);
        }
        if (email !== undefined) {
          params = params.set('email', `${email}`);
        }

        return this.httpClient.get<PaginatedResponse<DiaBackendContact>>(
          `${BASE_URL}/api/v3/contacts/`,
          { headers, params }
        );
      }),
      tap(() => this._isFetching$.next(false))
    );
  }
Example #11
Source File: dia-backend-auth.service.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
verifyPhoneVerification$(phoneNumber: string, verificationCode: string) {
    return defer(() => this.getAuthHeaders()).pipe(
      concatMap(headers =>
        this.httpClient.post<VerifyPhoneVerificationResponse>(
          `${BASE_URL}/auth/users/verify-phone-verification/`,
          { phone_number: phoneNumber, verification_code: verificationCode },
          { headers }
        )
      ),
      concatMapTo(this.readUser$()),
      concatMap(response => this.setPhoneVerfied(response.phone_verified))
    );
  }
Example #12
Source File: contacts.page.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
delete(contact: DiaBackendContact) {
    const action$ = this.diaBackendContactRepository
      .deleteByEmail$(contact.contact_email)
      .pipe(concatMapTo(this.diaBackendContactRepository.all$), first());
    return this.blockingActionService
      .run$(action$)
      .pipe(
        catchError((err: unknown) => this.errorService.toastError$(err)),
        untilDestroyed(this)
      )
      .subscribe();
  }
Example #13
Source File: dia-backend-auth.service.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
login$(email: string, password: string): Observable<LoginResult> {
    return this.httpClient
      .post<LoginResponse>(`${BASE_URL}/auth/token/login/`, {
        email,
        password,
      })
      .pipe(
        concatMap(response => this.setToken(response.auth_token)),
        concatMapTo(this.syncProfile$()),
        map(([username, _email]) => ({ username, email: _email }))
      );
  }
Example #14
Source File: profile.page.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
logout() {
    const action$ = defer(() => this.mediaStore.clear()).pipe(
      concatMapTo(defer(() => this.database.clear())),
      concatMapTo(defer(() => this.preferenceManager.clear())),
      concatMapTo(defer(reloadApp)),
      catchError((err: unknown) => this.errorService.toastError$(err))
    );
    return defer(() =>
      this.confirmAlert.present({
        message: this.translocoService.translate('message.confirmLogout'),
      })
    )
      .pipe(
        concatMap(result =>
          iif(() => result, this.blockingActionService.run$(action$))
        ),
        untilDestroyed(this)
      )
      .subscribe();
  }
Example #15
Source File: login.page.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
private resetPassword(email: string) {
    const action$ = defer(() =>
      this.diaBackendAuthService.resetPassword$(email)
    ).pipe(
      concatMapTo(
        defer(() =>
          this.alertController.create({
            header: this.translocoService.translate('resetPassword'),
            message: this.translocoService.translate(
              'message.resetPasswordEmailSent'
            ),
            buttons: [{ text: this.translocoService.translate('ok') }],
          })
        )
      ),
      concatMap(alertElement => alertElement.present()),
      catchError((err: unknown) => this.errorService.toastError$(err))
    );
    return defer(() => this.blockingActionService.run$(action$))
      .pipe(untilDestroyed(this))
      .subscribe();
  }
Example #16
Source File: login.page.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
onSubmit() {
    this.showResendEmailButton = false;

    const timeoutDue = 20000;
    const action$ = this.diaBackendAuthService
      .login$(this.model.email, this.model.password)
      .pipe(
        timeout(timeoutDue),
        catchError((err: unknown) => this.handleLoginError$(err)),
        tap(_ => (this.onboardingService.isNewLogin = true))
      );

    return this.blockingActionService
      .run$(action$, {
        message: this.translocoService.translate('message.pleaseWait'),
      })
      .pipe(
        concatMapTo(
          defer(() => this.router.navigate(['home'], { replaceUrl: true }))
        ),
        untilDestroyed(this)
      )
      .subscribe();
  }
Example #17
Source File: sending-post-capture.page.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
async send() {
    const action$ = combineLatest([this.asset$, this.receiverEmail$]).pipe(
      first(),
      switchTap(([asset, contact]) =>
        this.diaBackendTransactionRepository.add$({
          assetId: asset.id,
          targetEmail: contact,
          caption: this.message !== '' ? this.message : asset.caption,
          createContact: this.shouldCreateContact,
        })
      ),
      concatMap(([asset]) => this.removeAsset$(asset)),
      concatMapTo(defer(() => this.router.navigate(['/home']))),
      catchError((err: unknown) => this.errorService.toastError$(err))
    );

    const result = await this.confirmAlert.present({
      message: this.translocoService.translate('message.sendPostCaptureAlert'),
    });

    if (result) {
      this.blockingActionService
        .run$(action$)
        .pipe(untilDestroyed(this))
        .subscribe();
    }
  }
Example #18
Source File: inbox.page.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
accept(id: string) {
    const action$ = this.diaBackendTransactionRepository
      .accept$(id)
      .pipe(concatMapTo(this.diaBackendTransactionRepository.inbox$), first());

    this.blockingActionService
      .run$(action$)
      .pipe(
        catchError((err: unknown) => this.errorService.toastError$(err)),
        untilDestroyed(this)
      )
      .subscribe();
  }
Example #19
Source File: details.page.ts    From capture-lite with GNU General Public License v3.0 6 votes vote down vote up
private async remove() {
    const action$ = this.activeDetailedCapture$.pipe(
      first(),
      switchTap(activeDetailedCapture =>
        defer(() => {
          if (activeDetailedCapture.id) {
            return this.diaBackendAssetRepository.removeCaptureById$(
              activeDetailedCapture.id
            );
          }
          return VOID$;
        })
      ),
      concatMap(activeDetailedCapture => activeDetailedCapture.proof$),
      concatMap(proof => {
        if (proof) return this.proofRepository.remove(proof);
        return VOID$;
      }),
      catchError((err: unknown) => this.errorService.toastError$(err)),
      concatMapTo(defer(() => this.router.navigate(['..'])))
    );
    const result = await this.confirmAlert.present();
    if (result) {
      this.blockingActionService
        .run$(action$)
        .pipe(untilDestroyed(this))
        .subscribe();
    }
  }
Example #20
Source File: capacitor-filesystem-table.ts    From capture-lite with GNU General Public License v3.0 5 votes vote down vote up
readonly queryAll$ = defer(() => this.initialize()).pipe(
    concatMapTo(this.tuples$.asObservable()),
    isNonNullable()
  );
Example #21
Source File: web-crypto-api-signature-provider.service.spec.ts    From capture-lite with GNU General Public License v3.0 5 votes vote down vote up
describe('WebCryptoApiSignatureProvider', () => {
  let provider: WebCryptoApiSignatureProvider;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [SharedTestingModule],
    });
    provider = TestBed.inject(WebCryptoApiSignatureProvider);
  });

  it('should be created', () => expect(provider).toBeTruthy());

  it('should have ID', () => expect(provider.id).toBeTruthy());

  it('should get key pair by value after initialization', async () => {
    await provider.initialize();

    expect(await provider.getPublicKey()).toBeTruthy();
    expect(await provider.getPrivateKey()).toBeTruthy();
  });

  it('should get public key by Observable after initialization', done => {
    defer(() => provider.initialize())
      .pipe(concatMapTo(provider.publicKey$))
      .subscribe(result => {
        expect(result).toBeTruthy();
        done();
      });
  });

  it('should get private key by Observable after initialization', done => {
    defer(() => provider.initialize())
      .pipe(concatMapTo(provider.privateKey$))
      .subscribe(result => {
        expect(result).toBeTruthy();
        done();
      });
  });

  it('should initialize idempotently', async () => {
    await provider.initialize();
    const publicKey = await provider.getPublicKey();
    const privateKey = await provider.getPrivateKey();
    await provider.initialize();

    expect(await provider.getPublicKey()).toEqual(publicKey);
    expect(await provider.getPrivateKey()).toEqual(privateKey);
  });

  it('should provide signature', async () => {
    const signedMessage: SignedMessage = {
      spec_version: '',
      recorder: '',
      created_at: 0,
      proof_hash: '',
      asset_mime_type: '',
      caption: '',
      information: {},
    };
    const serializedSortedSignedMessage = JSON.stringify(
      sortObjectDeeplyByKey(signedMessage as any).toJSON()
    );
    const signature = await provider.provide(serializedSortedSignedMessage);

    expect(isSignature(signature)).toBeTrue();
  });
});
Example #22
Source File: capacitor-facts-provider.service.spec.ts    From capture-lite with GNU General Public License v3.0 5 votes vote down vote up
describe('CapacitorFactsProvider', () => {
  let provider: CapacitorFactsProvider;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [SharedTestingModule],
    });
    provider = TestBed.inject(CapacitorFactsProvider);
  });

  it('should be created', () => expect(provider).toBeTruthy());

  it('should have ID', () => expect(provider.id).toBeTruthy());

  it('should provide facts', async () => {
    const assets: Assets = {};

    const facts = await provider.provide(assets);

    expect(isFacts(facts)).toBeTrue();
  });

  it('should get if collecting device info enabled by value', async () => {
    const expected = true;

    await provider.setDeviceInfoCollection(expected);

    expect(await provider.isDeviceInfoCollectionEnabled()).toEqual(expected);
  });

  it('should get if collecting device info enabled by Observable', done => {
    const expected = true;

    defer(() => provider.setDeviceInfoCollection(expected))
      .pipe(concatMapTo(provider.isDeviceInfoCollectionEnabled$))
      .subscribe(result => {
        expect(result).toEqual(expected);
        done();
      });
  });

  it('should get if collecting location info enabled by value', async () => {
    const expected = true;

    await provider.setGeolocationInfoCollection(expected);

    expect(await provider.isGeolocationInfoCollectionEnabled()).toEqual(
      expected
    );
  });

  it('should get if collecting location info enabled by Observable', done => {
    const expected = true;

    defer(() => provider.setGeolocationInfoCollection(expected))
      .pipe(concatMapTo(provider.isGeolocationInfoCollectionEnabled$))
      .subscribe(result => {
        expect(result).toEqual(expected);
        done();
      });
  });
});
Example #23
Source File: blocking-action.service.ts    From capture-lite with GNU General Public License v3.0 5 votes vote down vote up
function run$<T>(action$: Observable<T>, loading: HTMLIonLoadingElement) {
  return defer(() => loading.present()).pipe(
    concatMapTo(action$),
    finalize(() => loading.dismiss())
  );
}
Example #24
Source File: error.service.ts    From capture-lite with GNU General Public License v3.0 5 votes vote down vote up
toastError$<T = unknown>(error: T) {
    return this.translocoService
      .selectTranslateObject<{ [key: string]: string }>('error')
      .pipe(
        first(),
        map(
          ({
            validationError,
            authenticationError,
            notFoundError,
            serverInternalError,
            internetError,
            timeoutError,
            unknownError,
          }) => {
            // eslint-disable-next-line no-debugger
            if (typeof error === 'string') return error;
            if (error instanceof HttpErrorResponse) {
              if (error.status === HttpErrorCode.INVALID)
                return validationError;
              if (error.status === HttpErrorCode.AUTHENTICATION)
                return authenticationError;
              if (error.status === HttpErrorCode.NOT_FOUND)
                return notFoundError;
              if (error.status >= HttpErrorCode.INTERNAL)
                return serverInternalError;
              return internetError;
            }
            if (error instanceof TimeoutError) return timeoutError;
            if (error instanceof Error) return error.message;
            return unknownError;
          }
        ),
        concatMap(
          message =>
            new Promise<T>(resolve =>
              this.toastController
                .create({ message, duration: 2000, color: 'danger' })
                .then(toast => toast.present())
                .then(() => {
                  console.error(error);
                  resolve(error);
                })
            )
        ),
        concatMapTo(EMPTY)
      );
  }
Example #25
Source File: signup.page.ts    From capture-lite with GNU General Public License v3.0 5 votes vote down vote up
onSubmit() {
    const action$ = this.diaBackendAuthService
      .createUser$(
        this.model.username,
        this.model.email,
        this.model.password,
        this.model.referralCodeOptional
      )
      .pipe(
        first(),
        concatMapTo(
          defer(() =>
            this.router.navigate(
              [
                '/login',
                { email: this.model.email, password: this.model.password },
              ],
              { replaceUrl: true }
            )
          )
        ),
        catchError((err: unknown) => {
          if (
            err instanceof HttpErrorResponse &&
            err.error.error?.type === 'duplicate_email'
          ) {
            return this.errorService.toastError$(
              this.translocoService.translate(
                'error.diaBackend.duplicate_email'
              )
            );
          }
          if (
            err instanceof HttpErrorResponse &&
            err.error.error?.details?.username?.length > 0
          ) {
            return this.errorService.toastError$(
              this.translocoService.translate(
                'error.diaBackend.duplicate_username'
              )
            );
          }
          if (
            err instanceof HttpErrorResponse &&
            err.error.error?.type === 'invalid_referral_code'
          ) {
            return this.errorService.toastError$(
              this.translocoService.translate(
                'error.diaBackend.invalid_referral_code'
              )
            );
          }
          // eslint-disable-next-line @typescript-eslint/no-magic-numbers
          if (err instanceof HttpErrorResponse && err.status === 401)
            return this.errorService.toastError$(
              this.translocoService.translate(
                'error.diaBackend.untrusted_client'
              )
            );
          return this.errorService.toastError$(err);
        })
      );

    this.blockingActionService
      .run$(action$)
      .pipe(untilDestroyed(this))
      .subscribe();
  }
Example #26
Source File: capacitor-filesystem-table.spec.ts    From capture-lite with GNU General Public License v3.0 4 votes vote down vote up
describe('CapacitorFilesystemTable', () => {
  let table: Table<TestTuple>;

  beforeEach(() => {
    const tableId = 'tableId';
    table = new CapacitorFilesystemTable(tableId, Filesystem);
  });

  afterEach(async () => table.drop());

  it('should be created', () => expect(table).toBeTruthy());

  it('should emit empty array with Observable on initial query', done => {
    table.queryAll$.subscribe(tuples => {
      expect(tuples).toEqual([]);
      done();
    });
  });

  it('should emit empty array with Promise on initial query', async () => {
    const tuples = await table.queryAll();
    expect(tuples).toEqual([]);
  });

  it('should emit new query on inserting tuple', done => {
    defer(async () => {
      await table.insert([TUPLE1]);
      await table.insert([TUPLE2]);
    })
      .pipe(concatMapTo(table.queryAll$))
      .subscribe(tuples => {
        expect(tuples).toEqual([TUPLE1, TUPLE2]);
        done();
      });
  });

  it('should throw on inserting same tuple', async () => {
    const sameTuple: TestTuple = { ...TUPLE1 };

    await expectAsync(table.insert([TUPLE1, sameTuple])).toBeRejected();
  });

  it('should throw on inserting same tuple with comparator', async () => {
    const sameIdTuple: TestTuple = { ...TUPLE2, id: TUPLE1_ID };

    await expectAsync(
      table.insert(
        [TUPLE1, sameIdTuple],
        OnConflictStrategy.ABORT,
        (x, y) => x.id === y.id
      )
    ).toBeRejected();
  });

  it('should throw on inserting existed tuple', async () => {
    const sameTuple: TestTuple = { ...TUPLE1 };
    await table.insert([TUPLE1]);

    await expectAsync(table.insert([sameTuple])).toBeRejected();
  });

  it('should throw on inserting existed tuple with comparator', async () => {
    const sameIdTuple: TestTuple = { ...TUPLE2, id: TUPLE1_ID };
    await table.insert([TUPLE1]);

    await expectAsync(
      table.insert(
        [sameIdTuple],
        OnConflictStrategy.ABORT,
        (x, y) => x.id === y.id
      )
    ).toBeRejected();
  });

  it('should ignore on inserting existed tuple if the conflict strategy is IGNORE', async () => {
    const sameTuple: TestTuple = { ...TUPLE1 };
    await table.insert([TUPLE1]);

    await table.insert([sameTuple, TUPLE2], OnConflictStrategy.IGNORE);

    const all = await table.queryAll();
    expect(all).toEqual([TUPLE1, TUPLE2]);
  });

  it('should ignore on inserting existed tuple with comparator if the conflict strategy is IGNORE', async () => {
    const sameIdTuple: TestTuple = { ...TUPLE2, id: TUPLE1_ID };
    await table.insert([TUPLE1]);

    await table.insert(
      [sameIdTuple, TUPLE2],
      OnConflictStrategy.IGNORE,
      (x, y) => x.id === y.id
    );

    const all = await table.queryAll();
    expect(all).toEqual([TUPLE1, TUPLE2]);
  });

  it('should replace on inserting existed tuple if the conflict strategy is REPLACE', async () => {
    const sameTuple: TestTuple = { ...TUPLE1 };
    await table.insert([TUPLE1]);

    await table.insert([sameTuple, TUPLE2], OnConflictStrategy.REPLACE);

    const all = await table.queryAll();
    expect(all).toEqual([sameTuple, TUPLE2]);
  });

  it('should replace on inserting existed tuple with comparator if the conflict strategy is REPLACE', async () => {
    const sameIdTuple: TestTuple = { ...TUPLE2, id: TUPLE1_ID };
    await table.insert([TUPLE1]);

    await table.insert(
      [sameIdTuple, TUPLE2],
      OnConflictStrategy.REPLACE,
      (x, y) => x.id === y.id
    );

    const all = await table.queryAll();
    expect(all).toEqual([sameIdTuple, TUPLE2]);
  });

  it('should remove by tuple contents not reference', done => {
    const sameTuple: TestTuple = { ...TUPLE1 };

    defer(async () => {
      await table.insert([TUPLE1]);
      await table.delete([sameTuple]);
    })
      .pipe(concatMapTo(table.queryAll$))
      .subscribe(tuples => {
        expect(tuples).toEqual([]);
        done();
      });
  });

  it('should not emit removed tuples', done => {
    const sameTuple1: TestTuple = { ...TUPLE1 };

    defer(async () => {
      await table.insert([TUPLE1, TUPLE2]);
      await table.delete([sameTuple1]);
    })
      .pipe(concatMapTo(table.queryAll$))
      .subscribe(tuples => {
        expect(tuples).toEqual([TUPLE2]);
        done();
      });
  });

  it('should not emit removed tuples with comparator', done => {
    const sameIdTuple1: TestTuple = { ...TUPLE2, id: TUPLE1_ID };

    defer(async () => {
      await table.insert([TUPLE1, TUPLE2]);
      await table.delete([sameIdTuple1], (x, y) => x.id === y.id);
    })
      .pipe(concatMapTo(table.queryAll$))
      .subscribe(tuples => {
        expect(tuples).toEqual([TUPLE2]);
        done();
      });
  });

  it('should throw on deleting non-existent tuples', async () => {
    await expectAsync(table.delete([TUPLE1])).toBeRejected();
  });

  it('should throw on deleting non-existent tuples with comparator', async () => {
    await table.insert([TUPLE1, TUPLE2]);

    await expectAsync(table.delete([TUPLE1], () => false)).toBeRejected();
  });

  it('should insert atomically', done => {
    const tupleCount = 100;
    const expectedTuples: TestTuple[] = [...Array(tupleCount).keys()].map(
      value => ({
        id: value,
        name: `${value}`,
        happy: true,
        skills: [],
        address: { country: '', city: '' },
      })
    );

    defer(() => Promise.all(expectedTuples.map(tuple => table.insert([tuple]))))
      .pipe(concatMapTo(table.queryAll$))
      .subscribe(tuples => {
        expect(tuples).toEqual(expectedTuples);
        done();
      });
  });

  it('should delete atomically', done => {
    const tupleCount = 100;
    const sourceTuple: TestTuple[] = [...Array(tupleCount).keys()].map(
      value => ({
        id: value,
        name: `${value}`,
        happy: true,
        skills: [],
        address: { country: '', city: '' },
      })
    );

    defer(async () => {
      await table.insert(sourceTuple);
      await Promise.all(sourceTuple.map(tuple => table.delete([tuple])));
    })
      .pipe(concatMapTo(table.queryAll$))
      .subscribe(tuples => {
        expect(tuples).toEqual([]);
        done();
      });
  });

  it('should wipe all data after clear', async () => {
    await table.insert([TUPLE1, TUPLE2]);

    await table.clear();

    expect(await table.queryAll()).toEqual([]);
  });

  it('should be able to reinitialize after clear', async () => {
    await table.insert([TUPLE1, TUPLE2]);
    await table.clear();

    await table.insert([TUPLE1]);

    expect(await table.queryAll()).toEqual([TUPLE1]);
  });

  it('should clear idempotently', async () => {
    await table.insert([TUPLE1]);

    await table.clear();
    await table.clear();

    expect(await table.queryAll()).toEqual([]);
  });

  it('should emit empty data after clear', done => {
    let counter = 0;

    table.queryAll$.subscribe(value => {
      if (counter === 0) {
        expect(value).toEqual([]);
      } else if (counter === 1) {
        expect(value).toEqual([TUPLE1]);
      } else if (counter === 2) {
        expect(value).toEqual([]);
        done();
      }
      counter += 1;
    });

    defer(async () => {
      await table.insert([TUPLE1]);
      await table.clear();
    }).subscribe();
  });

  it('should update proofs', done => {
    const tupleCount = 100;
    const sourceTuple: TestTuple[] = [...Array(tupleCount).keys()].map(
      value => ({
        id: value,
        name: `${value}`,
        happy: true,
        skills: [],
        address: { country: '', city: '' },
      })
    );
    const expectedTuple: TestTuple[] = [...Array(tupleCount).keys()].map(
      value => ({
        id: value,
        name: `${value}`,
        happy: false,
        skills: [],
        address: { country: '', city: '' },
      })
    );

    defer(async () => {
      await table.insert(sourceTuple);
      await table.update(expectedTuple, (x, y) => x.id === y.id);
    })
      .pipe(concatMapTo(table.queryAll$))
      .subscribe(tuples => {
        expect(tuples).toEqual(expectedTuple);
        done();
      });
  });
});
Example #27
Source File: capacitor-storage-preferences.spec.ts    From capture-lite with GNU General Public License v3.0 4 votes vote down vote up
describe('CapacitorStoragePreferences', () => {
  let preferences: Preferences;
  const id = 'id';

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [SharedTestingModule],
      providers: [{ provide: STORAGE_PLUGIN, useValue: Storage }],
    });
    const storagePlugin = TestBed.inject(STORAGE_PLUGIN);
    preferences = new CapacitorStoragePreferences(id, storagePlugin);
  });

  it('should be created', () => expect(preferences).toBeTruthy());

  it('should get the same ID set in constructor', () =>
    expect(preferences.id).toEqual(id));

  it('should get the default boolean Observable if not set previously', done => {
    const notExistedKey = 'unknown';
    const defaultValue = true;
    preferences.getBoolean$(notExistedKey, defaultValue).subscribe(result => {
      expect(result).toEqual(defaultValue);
      done();
    });
  });

  it('should get the default number Observable if not set previously', done => {
    const notExistedKey = 'unknown';
    const defaultValue = 999;
    preferences.getNumber$(notExistedKey, defaultValue).subscribe(result => {
      expect(result).toEqual(defaultValue);
      done();
    });
  });

  it('should get the default string Observable if not set previously', done => {
    const notExistedKey = 'unknown';
    const defaultValue = 'default';
    preferences.getString$(notExistedKey, defaultValue).subscribe(result => {
      expect(result).toEqual(defaultValue);
      done();
    });
  });

  it('should get the default boolean value if not set previously', async () => {
    const notExistedKey = 'unknown';
    const defaultValue = true;
    const bool = await preferences.getBoolean(notExistedKey, defaultValue);
    expect(bool).toEqual(defaultValue);
  });

  it('should get the default number value if not set previously', async () => {
    const notExistedKey = 'unknown';
    const defaultValue = 999;
    const num = await preferences.getNumber(notExistedKey, defaultValue);
    expect(num).toEqual(defaultValue);
  });

  it('should get the default string value if not set previously', async () => {
    const notExistedKey = 'unknown';
    const defaultValue = 'default';
    const str = await preferences.getString(notExistedKey, defaultValue);
    expect(str).toEqual(defaultValue);
  });

  it('should get the same boolean Observable set previously', done => {
    const key = 'key';
    const value = true;

    defer(() => preferences.setBoolean(key, value))
      .pipe(concatMapTo(preferences.getBoolean$(key)))
      .subscribe(result => {
        expect(result).toEqual(value);
        done();
      });
  });

  it('should get the same number Observable set previously', done => {
    const key = 'key';
    const value = 99;

    defer(() => preferences.setNumber(key, value))
      .pipe(concatMapTo(preferences.getNumber$(key)))
      .subscribe(result => {
        expect(result).toEqual(value);
        done();
      });
  });

  it('should get the same string Observable set previously', done => {
    const key = 'key';
    const value = 'value';

    defer(() => preferences.setString(key, value))
      .pipe(concatMapTo(preferences.getString$(key)))
      .subscribe(result => {
        expect(result).toEqual(value);
        done();
      });
  });

  it('should get the same boolean value set previously', async () => {
    const key = 'key';
    const value = true;
    await preferences.setBoolean(key, value);

    const result = await preferences.getBoolean(key);
    expect(result).toEqual(value);
  });

  it('should get the same number value set previously', async () => {
    const key = 'key';
    const value = 99;
    await preferences.setNumber(key, value);

    const result = await preferences.getNumber(key);
    expect(result).toEqual(value);
  });

  it('should get the same string value set previously', async () => {
    const key = 'key';
    const value = 'value';
    await preferences.setString(key, value);

    const result = await preferences.getString(key);
    expect(result).toEqual(value);
  });

  it('should set boolean atomically', done => {
    const key = 'key';
    const operationCount = 100;
    const lastBoolean = true;
    const booleans: boolean[] = [
      ...Array(operationCount - 1).fill(false),
      lastBoolean,
    ];

    defer(() =>
      Promise.all(booleans.map(bool => preferences.setBoolean(key, bool)))
    )
      .pipe(concatMapTo(preferences.getBoolean$(key)))
      .subscribe(result => {
        expect(result).toEqual(lastBoolean);
        done();
      });
  });

  it('should set number atomically', done => {
    const key = 'key';
    const operationCount = 100;
    const lastNumber = -20;
    const numbers: number[] = [...Array(operationCount - 1).keys(), lastNumber];

    defer(() => Promise.all(numbers.map(n => preferences.setNumber(key, n))))
      .pipe(concatMapTo(preferences.getNumber$(key)))
      .subscribe(result => {
        expect(result).toEqual(lastNumber);
        done();
      });
  });

  it('should set string atomically', done => {
    const key = 'key';
    const operationCount = 1000;
    const lastString = 'last';
    const strings: string[] = [
      ...`${Array(operationCount - 1).keys()}`,
      lastString,
    ];

    defer(() =>
      Promise.all(strings.map(str => preferences.setString(key, str)))
    )
      .pipe(concatMapTo(preferences.getString$(key)))
      .subscribe(result => {
        expect(result).toEqual(lastString);
        done();
      });
  });

  it('should remove all values after clear', done => {
    const booleanKey = 'booleanKey';
    const booleanValue = true;
    const defaultBooleanValue = false;
    const numberKey = 'numberKey';
    const numberValue = 77;
    const defaultNumberValue = 55;
    const stringKey = 'stringKey';
    const stringValue = 'stringValue';
    const defaultStringValue = 'defaultStringValue';

    defer(async () => {
      await preferences.setBoolean(booleanKey, booleanValue);
      await preferences.setNumber(numberKey, numberValue);
      await preferences.setString(stringKey, stringValue);

      await preferences.clear();
    })
      .pipe(
        concatMapTo(
          zip(
            preferences.getBoolean$(booleanKey, defaultBooleanValue),
            preferences.getNumber$(numberKey, defaultNumberValue),
            preferences.getString$(stringKey, defaultStringValue)
          )
        ),
        first()
      )
      .subscribe(([booleanResult, numberResult, stringResult]) => {
        expect(booleanResult).toEqual(defaultBooleanValue);
        expect(numberResult).toEqual(defaultNumberValue);
        expect(stringResult).toEqual(defaultStringValue);
        done();
      });
  });

  it('should clear idempotently', async () => {
    const key = 'key';
    const expected = 2;
    await preferences.setNumber(key, 1);

    await preferences.clear();
    await preferences.clear();

    expect(await preferences.getNumber(key, expected)).toEqual(expected);
  });
});
Example #28
Source File: proof-repository.service.spec.ts    From capture-lite with GNU General Public License v3.0 4 votes vote down vote up
describe('ProofRepository', () => {
  let repo: ProofRepository;
  let proof1: Proof;
  let proof2: Proof;
  let mediaStore: MediaStore;

  beforeEach(async () => {
    TestBed.configureTestingModule({
      imports: [SharedTestingModule],
    });
    mediaStore = TestBed.inject(MediaStore);
    repo = TestBed.inject(ProofRepository);
    proof1 = await Proof.from(
      mediaStore,
      PROOF1_ASSETS,
      PROOF1_TRUTH,
      PROOF1_SIGNATURES_VALID
    );
    proof2 = await Proof.from(
      mediaStore,
      PROOF2_ASSETS,
      PROOF2_TRUTH,
      PROOF2_SIGNATURES_INVALID
    );
  });

  it('should be created', () => expect(repo).toBeTruthy());

  it('should get empty array when query on initial status', done => {
    repo.all$.subscribe(proofs => {
      expect(proofs).toEqual([]);
      done();
    });
  });

  it('should emit new query on adding proof', done => {
    defer(() => repo.add(proof1))
      .pipe(concatMapTo(repo.all$))
      .subscribe(proofs => {
        expect(proofs.map(p => p.indexedAssets)).toEqual(
          [proof1].map(p => p.indexedAssets)
        );
        done();
      });
  });

  it('should not emit removed proofs', done => {
    defer(async () => {
      await repo.add(proof1);
      await repo.add(proof2);
      const sameProof1 = await Proof.from(
        mediaStore,
        PROOF1_ASSETS,
        PROOF1_TRUTH,
        PROOF1_SIGNATURES_VALID
      );

      await repo.remove(sameProof1);
    })
      .pipe(concatMapTo(repo.all$))
      .subscribe(proofs => {
        expect(proofs.map(p => p.indexedAssets)).toEqual(
          [proof2].map(p => p.indexedAssets)
        );
        done();
      });
  });

  it('should emit updated proof', done => {
    defer(() =>
      Proof.from(
        mediaStore,
        PROOF2_ASSETS,
        PROOF1_TRUTH,
        PROOF1_SIGNATURES_VALID
      )
    )
      .pipe(
        concatMap(sameTimestampProof =>
          defer(async () => {
            await repo.add(proof1);
            await repo.update(
              [sameTimestampProof],
              (x, y) => x.timestamp === y.timestamp
            );
          }).pipe(
            concatMapTo(repo.all$),
            tap(proofs =>
              expect(proofs.map(p => p.indexedAssets)).toEqual(
                [sameTimestampProof].map(p => p.indexedAssets)
              )
            )
          )
        )
      )
      .subscribe(() => done());
  });
});