Тестовый компонент React Context, содержащий как Context.Provider, так и Context.Consumer

Я пытаюсь протестировать компонент, содержащий как поставщика, так и потребителя контекста React. См. App.tsx ниже. Поставщик находится в классе-оболочке, который также обрабатывает состояние.

Как издеваться над классом-оболочкой ConfigurationContextProvider, чтобы он мог правильно предоставить значение loadedStatus потребителю для тестирования различных отрисовок App.tsx?

App.tsx:

    public render(): React.ReactNode {
    return (
      <ConfigurationContextProvider>
        <ConfigurationContext.Consumer>
          { ({ 
            loadedStatus,
          }): ReactElement => {
            switch( loadedStatus ){
              case ConfigStatus.GoodConfiguration:
                return ( this.renderApp());
              case ConfigStatus.NotLoaded:
                return ( this.renderUnloadedApp() );
              case ConfigStatus.BadConfiguration:
                return ( this.renderBadConfiguration() );
            }
          }}
        </ConfigurationContext.Consumer> 
      </ConfigurationContextProvider>
    )}

ContextProvider.tsx:

    export const ConfigurationContext = React.createContext<ConfigurationState | undefined>(undefined);

    export enum ConfigStatus {
      NotLoaded,
      BadConfiguration,
      GoodConfiguration
    }

    export interface ConfigurationState{
      loadedStatus: ConfigStatus;
      baseUrl: URL;
    }

    export class ConfigurationContextProvider extends Component< {}, ConfigurationState> {

      constructor( props: {} ){
        super(props);
        this.state = { 
          loadedStatus: ConfigStatus.NotLoaded,
          baseUrl: null
        }
      }

      async componentDidMount(): Promise<void> {
        await this.loadConfiguration();
      }

      setConfiguration(configuration: Response): void {
        const URL_KEY = 'BASE_URL';
        const URL_VALUE = configuration[URL_KEY];
        if (!Object.prototype.hasOwnProperty.call(configuration, URL_KEY))
        {
          this.setState({ loadedStatus: ConfigStatus.BadConfiguration });
          console.error(`Missing field in configs: ${ URL_KEY }`);
        }
        else {
          try{
            this.setState({
              loadedStatus: ConfigStatus.GoodConfiguration, 
              baseUrl: new URL(URL_VALUE),
            });
          }
          catch {
            this.setState({ loadedStatus: ConfigStatus.BadConfiguration });
            console.error(`Bad URL in environment configs - ${ URL_KEY } : ${ URL_VALUE }`);
          }
        }
      }

      loadConfiguration(): Promise<void> {
        const configPromise: Promise<Response> = fetch('./env.json');
        return configPromise.then( (response) => response.json())
          .then( (config: Response) => this.setConfiguration(config));
      }

      render(): React.ReactNode {
        return (
          <ConfigurationContext.Provider value = { { 
            ...this.state,
          } }>
            {this.props.children}
          </ConfigurationContext.Provider>
        )
      }
    }

person MicScoPau    schedule 07.04.2020    source источник


Ответы (1)


Самый простой способ - это spyOn loadConfig функции ConfigurationContextProvider и установка необходимых ответов для setConfig. Таким образом можно тестировать различные результаты и при необходимости полностью обновлять контекст / состояние.

jest.spyOn(
  ConfigurationContextProvider.prototype, 'loadConfiguration').mockImplementation(
    function(this: ConfigurationContextProvider) {
      this.setConfiguration( { BASE_URL: 'http://localhost:8080' });
      return Promise.resolve();
    }
);
person MicScoPau    schedule 30.04.2020