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

[POC] Testing utils for SSR Error Handling #19102

Open
wants to merge 57 commits into
base: develop
Choose a base branch
from
Open

Conversation

pawelfras
Copy link
Contributor

@pawelfras pawelfras commented Aug 2, 2024

This PR contains utils that help to test different SSR Error Handling scenarios without redeployment/re-building of the app each time we change the app configuration. It has been achieved by adding a service that reacts to the specific query params which control different behaviours:

export interface TestQueryParams {
  /**
   * Causes HTTP 404 error
   */
  pageNotFoundError?: boolean;
  /**
   * Causes HTTP 500 error
   */
  serverError?: boolean;
  /**
   * Causes error in NgRx flow, that eventually turns into 500 unknown server error
   */
  ngrxError?: boolean;
  /**
   * control `ssrStrictErrorHandlingForHttpAndNgrx` feature toggle. Enabled by default
   */
  enableSsrStrictErrorHandlingForHttpAndNgrx?: boolean;
  /**
   * control `propagateErrorsToServer` feature toggle. Enabled by default
   */
  enablePropagateErrorsToServer?: boolean;
  /** control whether SSR response contains custom status and header:
   * `x-custom-status: 203` and `status: 203`
   */
  customResponseStatus?: boolean;
  /**
   * Causes runtime error in component
   */
  runtimeErrorInComponent?: boolean;

  /**
   * Turn on ExpressJS error handler returning custom error page.
   */
  customErrorPage?: boolean;
}

Config for the fresh and migrated

Prerequisites:

  • build and deploy Spartacus packages locally:
    npx ts-node ./tools/schematics/testing.ts in the SPA root folder`
  • install packages in the fresh app or the migrated app
    Note: For migrated app, use Angular 17.0.5 because the latest Angular 17 version causes dependencies issue

To use it in a fresh and migrated application, additional adjustments are required:

  • in app.component.ts, add the following snippet to be able triggering runtime error in a component:
constructor() {
  if (inject(TestQueryParamsService).queryParams.runtimeErrorInComponent) {
    throw new Error('Runtime error in root component');
  }
}
  • in app.module.ts, provide following factories that gives ability to control feature toggles and override endpoints for causing HTTP errors:
    provideFeatureTogglesFactory(() => {
      const {
        enablePropagateErrorsToServer,
        enableSsrStrictErrorHandlingForHttpAndNgrx,
      } = inject(TestQueryParamsService).queryParams;
      return {
        ssrStrictErrorHandlingForHttpAndNgrx:
          enableSsrStrictErrorHandlingForHttpAndNgrx,
        propagateErrorsToServer: enablePropagateErrorsToServer,
      };
    }),
    provideConfigFactory(() => {
      const { pageNotFoundError, serverError } = inject(
        TestQueryParamsService
      ).queryParams;
      return {
        backend: {
          occ: {
            endpoints: {
              pages: pageNotFoundError ? '/cms/pages2' : '/cms/pages',
              components: serverError ? '/cms/components2' : '/cms/components',
            },
          },
        },
      };
    }),
  • Last but not least, you need to adjust server.ts file to manipulate ssr optimization options in runtime:
const ngExpressEngine1 = NgExpressEngineDecorator.get(engine, {
  cache: true,
  featureToggles: {
    avoidCachingErrors: true,
  },
})({
  bootstrap: AppServerModule,
});

const ngExpressEngine2 = NgExpressEngineDecorator.get(engine, {
  cache: true,
  shouldCacheRenderingResult: () => true,
  featureToggles: {
    avoidCachingErrors: true,
  },
})({
  bootstrap: AppServerModule,
});

const ngExpressEngine3 = NgExpressEngineDecorator.get(engine, {
  cache: true,
  shouldCacheRenderingResult: () => false,
  featureToggles: {
    avoidCachingErrors: false,
  },
})({
  bootstrap: AppServerModule,
});

const ngExpressEngineDefault = NgExpressEngineDecorator.get(engine)({
  bootstrap: AppServerModule,
});

const ngExpressEngineWrapper = (
  filePath: string,
  options: object,
  callback: any
) => {
  const ngExpressEngineInstance = String(
    (options as any).req.query.ngExpressEngineInstance
  );
  switch (ngExpressEngineInstance) {
    case '1':
      console.log('ngExpressEngineInstance 1');
      return ngExpressEngine1(filePath, options, callback);
    case '2':
      console.log('ngExpressEngineInstance 2');
      return ngExpressEngine2(filePath, options, callback);
    case '3':
      console.log('ngExpressEngineInstance 3');
      return ngExpressEngine3(filePath, options, callback);
    default:
      console.log('ngExpressEngineInstance default');
      return ngExpressEngineDefault(filePath, options, callback);
  }
};

export function app() {
  /* ... */

  //  server.engine(
  //    'html',
  //    ngExpressEngine({
  //      bootstrap: AppServerModule,
  //    })
  //  );
  server.engine('html', ngExpressEngineWrapper);

  /* ... */

  server.use(customErrorPageErrorHandlers); // <--- required to trigger custom error page 
}

How to use it?

Combine chosen query params in the URL regarding the testing scenario, e.g:

http://localhost:4000/electronics-spa/en/USD/?customErrorPage=true&runtimeErrorInComponent=true

to simulate 404 and enable a custom error page which results in the following page:
image

Note: Query params have to be set each time page is reloaded.

⚠️ Warning: To test whether the app still uses Angular default error handling for runtime errors related to APP_INITIALIZER if SSR Error Handling feature toggles are set to false, all ExpressJS error handlers have to be removed from the server.ts file. I haven't found a way to disable ExpressJS error handlers in runtime (unfortunately if condition inside the error handler isn't enough). That said, an application needs to be rebuilt (and re-deployed in case of testing on CCv2) after the mentioned adjustments in the server file.

Platonn and others added 30 commits July 10, 2023 10:54
Previous behavior: When `/products` endpoint returned a http error, the code broke in [this line](https://github.com/SAP/spartacus/blob/ed1e1a78c488b1e1214491ffa736612287f8cf70/projects/core/src/product/store/effects/product.effect.ts#L77), complaining that `this` is undefined.

Fix: Preserve the context of `this` which was lost in [this line](https://github.com/SAP/spartacus/blob/ed1e1a78c488b1e1214491ffa736612287f8cf70/projects/core/src/product/store/effects/product.effect.ts#L52)

The problem was revealed only after we implemented [CXSPA-2251](https://jira.tools.sap/browse/CXSPA-2251) where we referenced `this` by adding `this.logger` to the method `ProductEffects.productLoadEffect`

fixes https://jira.tools.sap/browse/CXSPA-3902
Co-authored-by: Krzysztof Platis <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Krzysztof Platis <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
# Conflicts:
#	projects/core/src/product/store/actions/product-references.action.ts
#	projects/core/src/product/store/actions/product-reviews.action.ts
#	projects/core/src/product/store/effects/product-reviews.effect.ts
#	projects/core/src/state/utils/entity-loader/entity-loader.action.ts
This pull request introduces methodologies for integrating multiple error interceptors that manage errors within the Server-Side Rendering (SSR) framework. This architectural augmentation preserves backward compatibility, mitigating any potential disruptions for end-users upon the incorporation of new error interceptors into the system.

With the introduction of this enhancement, it becomes easier for users to include new error interceptors, giving them the flexibility to determine the order in which these interceptors are applied within the system. This priority setting allows users to control how these interceptors operate and influence the workflow of the system.

The order is:
High priority
Normal or no priority
Low priority

Preserves the original order within a group of interceptors with the same priority.
In the past PR #17657 within this Epic branch, we made a lot of breaking changes. In that past PR we've also renamed public a lot of properties `public payload: any` to `public error: any` which was also a breaking change.

In this PR, we:
- revert those breaking changes.
  - bring back `public payload` property, if it was renamed to `public error`
  - bring back type `any` for `payload`/`error` properties that were changed to `ErrorActionType`
  - bring back the optional marker (`?`) for `payload`/`error`, that got removed the optional marker (`?`) 
  - bring back the old order of arguments of `EntityScopedFailAction`: `scope, error` vs `error, scope`
- additionally, we:
  - deprecate the signatures with the optional marker on the `payload`/`error` property, in favor of required params
  - widen type of `payload`/`error` to `any` from too-specific types like `ErrorModel`
  - pass missing `payload`/`error` parameter to super actions (like `ErrorActionType` etc.)
- fix some unit tests as a result of all above changes

Note for a reviewer:
The PR #19037 (not meant to be merged!) contains a full diff between this branch and the `develop` branch. You may want to check it to verify the current branch `feature/CXSPA-7198--v2` when merged to `epic/ssr-error-handling` will _really_ help to avoid _all_ breaking changes (related to ngrx actions) against `develop`

fixes https://jira.tools.sap/browse/CXSPA-7198
@pawelfras pawelfras requested a review from a team as a code owner August 2, 2024 11:27
Base automatically changed from epic/ssr-error-handling to develop September 10, 2024 18:41
@FollowTheFlo FollowTheFlo requested review from a team as code owners September 10, 2024 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants