Реактивный компонент тестирования контекста, который содержит и Context.Provider, и Context.Consumer - PullRequest
1 голос
/ 07 апреля 2020

Я пытаюсь протестировать компонент, который содержит как поставщика, так и потребителя React Context. Смотрите 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>
        )
      }
    }

1 Ответ

0 голосов
/ 01 мая 2020

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

jest.spyOn(
  ConfigurationContextProvider.prototype, 'loadConfiguration').mockImplementation(
    function(this: ConfigurationContextProvider) {
      this.setConfiguration( { BASE_URL: 'http://localhost:8080' });
      return Promise.resolve();
    }
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...