@testing-library/react#queryByTestId JavaScript Examples

The following examples show how to use @testing-library/react#queryByTestId. 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: CommentList.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("CommentList component", () => {
    let wrapper;
    beforeEach(() => {
        const comment =  <Comment author="alvarogarinf" text="This is a test" date="2020-4-29"></Comment>;
        const { container } = render(
                <CommentList comments={[comment]}></CommentList>
        );
        wrapper = container;
    });

    describe("renders correctly", () => {
        test("comments", () => {
            waitForElement(() => {
                expect(queryByTestId(wrapper, "comments")).not.toBeNull();
            });
        });

    });

});
Example #2
Source File: CourseAuthoringPage.test.jsx    From frontend-app-course-authoring with GNU Affero General Public License v3.0 6 votes vote down vote up
describe('DiscussionsSettings', () => {
  beforeEach(() => {
    initializeMockApp({
      authenticatedUser: {
        userId: 3,
        username: 'abc123',
        administrator: true,
        roles: [],
      },
    });

    store = initializeStore();
    axiosMock = new MockAdapter(getAuthenticatedHttpClient());
  });

  test('renders permission error in case of 403', async () => {
    await mockStore();
    renderComponent();
    expect(queryByTestId(container, 'permissionDeniedAlert')).toBeInTheDocument();
  });
});
Example #3
Source File: UploadButton.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("State is resetet when the prop 'reset' is provided", () => {
    test("state resets for single file button", () => {
        rerenderFunc(<UploadButton onChange={(e) => e} text="No file selected" reset></UploadButton>);
        waitForElement(() => {
            expect(queryByTestId(uploadButton, "upload-button-label").textContent).toBe("No file selected");
        });
    });
    test("state resets for multiple file button", () => {

    });
});
Example #4
Source File: UploadButton.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("Upload an element to a single file button", () => {
    test("label changes accordingly with the name of the file uploaded in single file button", () => {
        let filename = "test.png";
        let mockFile = new File(["test"], filename, {type: "image/png"});

        Object.defineProperty(input, "files", {
            value: [mockFile]
        });
        fireEvent.change(input);
      waitForElement(() => {
        expect(queryByTestId(uploadButton, "upload-button-label").textContent).toBe(filename);
      });
    });


    test("label changes accordingly with the name of the file uploaded in multiple file button", () => {
        let mockFile1 = new File(["test1"], "filename1.png", {type: "image/png"});
        let mockFile2 = new File(["test2"], "filename2.png", {type: "image/png"});
        let mockFile3 = new File(["test3"], "filename3.png", {type: "image/png"});

        let myRef = React.createRef();
        rerenderFunc(<UploadButton text="No images" ref={myRef} onChange={(e) => e} multiple></UploadButton>);
        waitForElement(() => {
            Object.defineProperty(input, "files", {
                value: [mockFile1, mockFile2, mockFile3]
            });
            fireEvent.change(input);
            expect(queryByTestId(uploadButton, "upload-button-label").textContent).toBe("3 files selected");
        });
    });
});
Example #5
Source File: UploadButton.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("Everything is rendered correctly", () => {
    test("label is correctly displayed when there are no files selected for a single file button", () => {
        waitForElement(() => {
            expect(queryByTestId(uploadButton, "upload-button-label").textContent).toBe("No images selected");
        });
    });
    test("label is correctly displayed when there are no files selected for a multple file button", () => {
        rerenderFunc(<UploadButton multiple text="No files selected" onChange={(e) => e}></UploadButton>);
        waitForElement(() => {
            expect(queryByTestId(uploadButton, "upload-button-label").textContent).toBe("No files selected");
        });
    });

});
Example #6
Source File: Settings.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("Settings Component", () => {
  test("Component renders correctly", () => {
    expect(queryByTestId(wrapper, "settings-title")).not.toBeNull();
    expect(queryByTestId(wrapper, "settings-language")).not.toBeNull();
    expect(queryByTestId(wrapper, "settings-language-english")).toBeNull();
    expect(queryByTestId(wrapper, "settings-language-spanish")).toBeNull();
    expect(queryByTestId(wrapper, "settings-language-dropdown")).not.toBeNull();
  });

  beforeEach(() => {
    let dropdown = queryByTestId(wrapper, "settings-language-dropdown");
    fireEvent.click(dropdown);
  });

  describe("Change theme function", () => {
    test("english", () => {
      waitForDomChange(() => {
        let language = queryByTestId(wrapper, "settings-language-english");
        expect(language).not.toBeNull();
        fireEvent.click(language);
        expect(myMockLanguage).toBeCalled();
      });
    });

    test("spanish", () => {
      waitForDomChange(() => {
        let language = queryByTestId(wrapper, "settings-language-spanish");
        expect(language).not.toBeNull();
        fireEvent.click(language);
        expect(myMockLanguage).toBeCalled();
      });
    });
  });
});
Example #7
Source File: PageNotFound.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("PageNotFound Component", () => {
  describe("Component renders", () => {
    let wrapper;
    beforeEach(() => {
      const { container, rerenders } = render(
        <IntlProvider key={"en"} locale={"en"} messages={locales["en"]}>
          <PageNotFound />
        </IntlProvider>
      );
      wrapper = container;
    });

    test("Renders without errors", () => {
      expect(queryByTestId(wrapper, "page-not-found-container")).not.toBeNull();
    });
  });
});
Example #8
Source File: Notifications.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("Notifications component", () => {

    let component;

    beforeAll(() => {
        const {container, rerender} = render(<IntlProvider messages={locales["en"]} locale="en"><Notifications></Notifications></IntlProvider>);
        component = container;
    });

    describe("renders correctly", () => {
        test("div", () => {
            expect(queryByTestId(component, "notifications-div")).not.toBeNull();
        });
        test("list", () => {
            waitForElement(() => {
                expect(queryByTestId(component, "notifications-list")).not.toBeNull();
            });
        });
    });
});
Example #9
Source File: Notification.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("Notification component", () => {

    const mockNot = {
        text: "Esto es una prueba"
    };

    let component;

    beforeEach(() => {
        const {container, rerender} = render(<Notification notification={mockNot}></Notification>);
        component = container;
    });

    describe("renders correctly", () => {
        test("card", () => {
            expect(component).not.toBe(null);
            expect(queryByTestId(component, "notification-card")).not.toBe(null);
        });
    });

    test("content", () => {
        waitForElement(() => {
            expect(queryByTestId(component, "notification-card-text").innerHTML).toBe(mockNot.text);
        });
    });
});
Example #10
Source File: Modal.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("Buttons are rendered with different settings", () => {
  test("render save button but not cancel button", () => {
    rerenderFunc(
      <ViadeModal title="Title" onOpen={mock} saveText="Save"></ViadeModal>
    );
    waitForElement(() => {
      fireEvent.click(queryByTestId(modal, "modalButton"));
      waitForDomChange(() => {
        expect(queryByTestId(modal, "modalSaveButton")).not.toBeNull();
        expect(queryByTestId(modal, "modalCancelButton")).toBeNull();
        expect(queryByTestId(modal, "modalSaveButton")).toBe("Save");
      });
    });
  });

  test("render cancel button but not save button", () => {
    rerenderFunc(
      <ViadeModal title="Title" onOpen={mock} CancelText="Cancel"></ViadeModal>
    );
    waitForElement(() => {
      fireEvent.click(queryByTestId(modal, "modalButton"));
      waitForDomChange(() => {
        expect(queryByTestId(modal, "modalCancelButton")).not.toBeNull();
        expect(queryByTestId(modal, "modalSaveButton")).toBeNull();
        expect(queryByTestId(modal, "modalCancelButton")).toBe("Cancel");
      });
    });
  });
});
Example #11
Source File: Login.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("login component", () => {
  test("renders the header correctly", async () => {
    const text = "Login";
    waitForElement(() => {
      expect(queryByTestId(rendered, "login-header")).toEqual("Login");
      expect(queryByTestId(rendered, "login-header")).not.toBeNull();
    });
  });

  test("pop up opens up", () => {
    waitForElement(() => {
      global.open = jest.fn();
      fireEvent.click(queryByText(rendered, "Login here!"));
      expect(global.open).toBeCalled();
    });
  });
});
Example #12
Source File: Footer.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("Footer component", () => {
  let wrapper;
  beforeEach(() => {
    const { container } = render(
      <IntlProvider key={"en"} locale={"en"} messages={locales["en"]}>
        <Footer></Footer>
      </IntlProvider>
    );
    wrapper = container;
  });

  describe("renders correctly", () => {
    test("footer", () => {
      waitForElement(() => {
        expect(queryByTestId(wrapper, "footer")).toBeNull();
      });
    });

    test("team", () => {
      waitForElement(() => {
        expect(queryByTestId(wrapper, "footer-team")).toBeNull();
      });
    });

    test("github", () => {
      waitForElement(() => {
        expect(queryByTestId(wrapper, "footer-github")).not.toBeNull();
      });
    });

    test("react", () => {
      waitForElement(() => {
        expect(queryByTestId(wrapper, "footer-react")).not.toBeNull();
      });
    });
  });
});
Example #13
Source File: MyMap.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("MyMap Component", () => {

    let wrapper;
    let wrapperb;
    beforeEach(() => {
        const props = {
            center: [[43.360976539, -5.831938919]],
            positions: []
        };
        wrapper = myMap(props.center, props.positions);
        wrapperb = <MyMap center={props.center} positions={props.positions}></MyMap>;
    });
    
    test("Component renders correctly", () => {
        waitForElement(() => {
            expect(wrapperb.prop("positions")).not.toBeNull();
            expect(wrapperb.prop("center")).not.toBeNull();
            expect(queryByTestId(wrapper, "mymap-container")).not.toBeNull();
            expect(queryByTestId(wrapper, "mymap-map")).not.toBeNull();
            expect(queryByTestId(wrapper, "mymap-tilelayer")).not.toBeNull();
            expect(queryByTestId(wrapper, "mymap-polyline")).not.toBeNull();
        });
    });

});
Example #14
Source File: Comment.test.js    From viade_en1b with MIT License 6 votes vote down vote up
describe("Comment component", () => {
    let wrapper;
    beforeEach(() => {
        const { container } = render(
                <Comment author="alvarogarinf" text="This is a test" date="2020-4-29"></Comment>
        );
        wrapper = container;
    });

    describe("renders correctly", () => {
        test("comment", () => {
            waitForElement(() => {
                expect(queryByTestId(wrapper, "comment")).not.toBeNull();
            });
        });

        test("date", () => {
            waitForElement(() => {
                expect(queryByTestId(wrapper, "date")).not.toBeNull();
            });
        });

        test("text", () => {
            waitForElement(() => {
                expect(queryByTestId(wrapper, "text")).not.toBeNull();
            });
        });

        test("text", () => {
            waitForElement(() => {
                expect(queryByTestId(wrapper, "text")).not.toBeNull();
            });
        });

    });

});
Example #15
Source File: NotificationsList.test.js    From viade_en1b with MIT License 5 votes vote down vote up
describe("Notifications list component", () => {

    const mockWebId = "http://piratillajudoka.inrupt.net/profile/card#me";
    const mockLoad = jest.fn();

    let component;

    beforeEach(() => {
        const { container, rerender } = render(<IntlProvider messages={locales["en"]} locale="en"><NotificationsList userWebId={mockWebId} loadRoutes={mockLoad}></NotificationsList></IntlProvider>);
        component = container;
    });

    describe("renders correctly", () => {
        test("div", () => {
            expect(component).not.toBeNull();
            expect(queryByTestId(component, "notificationslist-div")).not.toBeNull();
        });
        test("list", () => {
            expect(component).not.toBeNull();
            expect(queryByTestId(component, "notificationslist-divcomponent")).not.toBeNull();
        });
        test("button", () => {
            expect(component).not.toBeNull();
            waitForElement(() => {
                expect(queryByTestId(component, "notificationslist-button")).not.toBeNull();
            });
        });
    });

    test("notifications", () => {
        waitForElement(() => {
            expect(queryAllByTestId(component, "notification")).not.toBeNull();
        });
    });

    test("click", () => {
        waitForElement(() => {
            fireEvent.click(queryByTestId(component, "notificationslist-button"));
            expect(mockLoad).toBeCalled();
        });

    });
});
Example #16
Source File: BbbSettings.test.jsx    From frontend-app-course-authoring with GNU Affero General Public License v3.0 5 votes vote down vote up
describe('BBB Settings', () => {
  beforeEach(async () => {
    initializeMockApp({
      authenticatedUser: {
        userId: 3,
        username: 'abc123',
        administrator: false,
        roles: [],
      },
    });
    store = initializeStore(initialState);
    axiosMock = new MockAdapter(getAuthenticatedHttpClient());
    history.push(liveSettingsUrl);
  });

  test('Plan dropdown to be visible and enabled in UI', async () => {
    await mockStore({ emailSharing: true });
    renderComponent();

    const spinner = getByRole(container, 'status');
    await waitForElementToBeRemoved(spinner);

    expect(queryByTestId(container, 'plansDropDown')).toBeInTheDocument();
    expect(container.querySelector('select[name="tierType"]')).not.toBeDisabled();
  });

  it('Plan dropdown should display correct number of options', async () => {
    await mockStore({ emailSharing: true });
    renderComponent();
    const spinner = getByRole(container, 'status');
    await waitForElementToBeRemoved(spinner);
    const dropDown = queryByTestId(container, 'plansDropDown');
    expect(getAllByRole(dropDown, 'option').length).toBe(3);
  });

  test('Connect to support and PII sharing message is visible and plans selection is disabled, When pii sharing is disabled, ',
    async () => {
      await mockStore({ piiSharingAllowed: false });
      renderComponent();
      const spinner = getByRole(container, 'status');
      await waitForElementToBeRemoved(spinner);
      const requestPiiText = queryByTestId(container, 'request-pii-sharing');
      const helpRequestPiiText = queryByTestId(container, 'help-request-pii-sharing');
      expect(requestPiiText).toHaveTextContent(
        messages.requestPiiSharingEnableForBbb.defaultMessage.replaceAll('{provider}', 'BigBlueButton'),
      );
      expect(helpRequestPiiText).toHaveTextContent(messages.piiSharingEnableHelpTextBbb.defaultMessage);
      expect(container.querySelector('select[name="tierType"]')).toBeDisabled();
    });

  test('free plans message is visible when free plan is selected', async () => {
    await mockStore({ emailSharing: true, isFreeTier: true });
    renderComponent();
    const spinner = getByRole(container, 'status');
    await waitForElementToBeRemoved(spinner);
    const dropDown = container.querySelector('select[name="tierType"]');
    userEvent.selectOptions(
      dropDown,
     getByRole(dropDown, 'option', { name: 'Free' }),
    );
    expect(queryByTestId(container, 'free-plan-message')).toBeInTheDocument();
    expect(queryByTestId(container, 'free-plan-message')).toHaveTextContent(messages.freePlanMessage.defaultMessage);
  });
});
Example #17
Source File: FeaturesTable.test.jsx    From frontend-app-course-authoring with GNU Affero General Public License v3.0 5 votes vote down vote up
describe('FeaturesTable', () => {
  let apps;
  let features;
  let container;

  beforeEach(() => {
    apps = [
      {
        externalLinks: {},
        featureIds: ['discussion-page', 'embedded-course-sections', 'wcag-2.1'],
        hasFullSupport: false,
        id: 'legacy',
      },
      {
        externalLinks: {},
        featureIds: ['discussion-page', 'basic-configuration'],
        hasFullSupport: false,
        id: 'piazza',
      }];

    features = [
      { id: 'discussion-page', featureSupportType: 'basic' },
      { id: 'embedded-course-sections', featureSupportType: 'full' },
      { id: 'wcag-2.1', featureSupportType: 'partial' },
      { id: 'basic-configuration', featureSupportType: 'common' },
    ];

    const wrapper = render(
      <IntlProvider locale="en">
        <FeaturesTable
          apps={apps}
          features={features}
        />
      </IntlProvider>,
    );
    container = wrapper.container;
  });

  test('displays a table, a thead, a tbody', () => {
    expect(container.querySelectorAll('table')).toHaveLength(1);
    expect(container.querySelectorAll('table > thead')).toHaveLength(1);
    expect(container.querySelectorAll('table > tbody')).toHaveLength(1);
  });

  test('displays a row for each available feature', () => {
    expect(container.querySelectorAll('tbody > tr')).toHaveLength(8);
  });

  test('apps columns receive a check for each feature they support', () => {
    features.forEach((feature) => {
      apps.forEach(app => {
        if (app.featureIds.includes(feature.id)) {
          const columnId = `${app.id}-${feature.id.replaceAll('.', '-')}`;
          const columnCell = queryByTestId(container, columnId);

          expect(columnCell.querySelector('#check-icon')).toBeInTheDocument();
        }
      });
    });
  });

  test('apps columns receive a dash for each unsupported feature', () => {
    features.forEach((feature) => {
      apps.forEach(app => {
        if (!app.featureIds.includes(feature.id)) {
          const columnId = `${app.id}-${feature.id.replaceAll('.', '-')}`;
          const columnCell = queryByTestId(container, columnId);

          expect(columnCell.querySelector('#remove-icon')).toBeInTheDocument();
        }
      });
    });
  });
});
Example #18
Source File: DiscussionsSettings.test.jsx    From frontend-app-course-authoring with GNU Affero General Public License v3.0 5 votes vote down vote up
describe.each([
  { piiSharingAllowed: false },
  { piiSharingAllowed: true },
])('PII sharing fields test', ({ piiSharingAllowed }) => {
  const enablePIISharing = false;

  beforeEach(() => {
    initializeMockApp({
      authenticatedUser: {
        userId: 3,
        username: 'abc123',
        administrator: true,
        roles: [],
      },
    });

    store = initializeStore({
      models: {
        courseDetails: {
          [courseId]: {},
        },
      },
    });
    axiosMock = new MockAdapter(getAuthenticatedHttpClient());

    // Leave the DiscussionsSettings route after the test.
    history.push(`/course/${courseId}/pages-and-resources`);
    axiosMock.onGet(getDiscussionsProvidersUrl(courseId))
      .reply(200, generateProvidersApiResponse(false));
    axiosMock.onGet(getDiscussionsSettingsUrl(courseId))
      .reply(200, generatePiazzaApiResponse(piiSharingAllowed));
    renderComponent();
  });

  test(`${piiSharingAllowed ? 'shows PII share username/email field when piiSharingAllowed is true'
    : 'hides PII share username/email field when piiSharingAllowed is false'}`, async () => {
    history.push(`/course/${courseId}/pages-and-resources/discussion`);

    // This is an important line that ensures the spinner has been removed - and thus our main
    // content has been loaded - prior to proceeding with our expectations.
    await waitForElementToBeRemoved(screen.getByRole('status'));

    userEvent.click(queryByLabelText(container, 'Select Piazza'));
    userEvent.click(queryByText(container, messages.nextButton.defaultMessage));
    await waitForElementToBeRemoved(screen.getByRole('status'));
    if (enablePIISharing) {
      expect(queryByTestId(container, 'piiSharingFields')).toBeInTheDocument();
    } else {
      expect(queryByTestId(container, 'piiSharingFields')).not.toBeInTheDocument();
    }
  });
});
Example #19
Source File: DiscussionsSettings.test.jsx    From frontend-app-course-authoring with GNU Affero General Public License v3.0 5 votes vote down vote up
describe.each([
  { isAdmin: false, isAdminOnlyConfig: false },
  { isAdmin: false, isAdminOnlyConfig: true },
  { isAdmin: true, isAdminOnlyConfig: false },
  { isAdmin: true, isAdminOnlyConfig: true },
])('LTI Admin only config test', ({ isAdmin, isAdminOnlyConfig }) => {
  beforeEach(() => {
    initializeMockApp({
      authenticatedUser: {
        userId: 3,
        username: 'abc123',
        administrator: isAdmin,
        roles: [],
      },
    });

    store = initializeStore({
      models: {
        courseDetails: {
          [courseId]: {},
        },
      },
    });
    axiosMock = new MockAdapter(getAuthenticatedHttpClient());

    // Leave the DiscussionsSettings route after the test.
    history.push(`/course/${courseId}/pages-and-resources`);
    axiosMock.onGet(getDiscussionsProvidersUrl(courseId))
      .reply(200, generateProvidersApiResponse(isAdminOnlyConfig));
    axiosMock.onGet(getDiscussionsSettingsUrl(courseId))
      .reply(200, generatePiazzaApiResponse(true));
    renderComponent();
  });

  test(`successfully advances to settings step for lti when adminOnlyConfig=${isAdminOnlyConfig} and user ${isAdmin ? 'is' : 'is not'} admin `, async () => {
    const showLTIConfig = isAdmin;
    history.push(`/course/${courseId}/pages-and-resources/discussion`);

    // This is an important line that ensures the spinner has been removed - and thus our main
    // content has been loaded - prior to proceeding with our expectations.
    await waitForElementToBeRemoved(screen.getByRole('status'));

    userEvent.click(queryByLabelText(container, 'Select Piazza'));
    userEvent.click(queryByText(container, messages.nextButton.defaultMessage));
    await waitForElementToBeRemoved(screen.getByRole('status'));

    if (showLTIConfig) {
      expect(queryByText(container, ltiMessages.formInstructions.defaultMessage)).toBeInTheDocument();
      expect(queryByTestId(container, 'ltiConfigFields')).toBeInTheDocument();
    } else {
      expect(queryByText(container, ltiMessages.formInstructions.defaultMessage)).not.toBeInTheDocument();
      expect(queryByTestId(container, 'ltiConfigFields')).not.toBeInTheDocument();
    }
  });
});
Example #20
Source File: App.test.js    From viade_en1b with MIT License 5 votes vote down vote up
describe("App Component", () => {
  test("Component renders correctly", () => {
    expect(queryByTestId(wrapper, "theApp")).not.toBeNull();
    expect(queryByTestId(wrapper, "theNavBar")).toBeNull();
  });
});
Example #21
Source File: Comments.test.js    From viade_en1b with MIT License 5 votes vote down vote up
describe("Comments component", () => {
    let wrapper;
    beforeEach(() => {
        const { container } = render(
            <IntlProvider key={"en"} locale={"en"} messages={locales["en"]}>
                <Comments userWebId='1'></Comments>
                </IntlProvider>
        );
        wrapper = container;
    });

    describe("renders correctly", () => {
        test("comments general", () => {
            waitForElement(() => {
                expect(queryByTestId(wrapper, "general-component")).not.toBeNull();
            });
        });

        test("comments modal", () => {
            waitForElement(() => {
                expect(queryByTestId(wrapper, "Modal-component")).not.toBeNull();
            });
        });

        test("comment form", () => {
            waitForElement(() => {
                expect(queryByTestId(wrapper, "form-component")).not.toBeNull();
            });
        });

        test("comment text area", () => {
            waitForElement(() => {
                expect(queryByTestId(wrapper, "textarea-component")).not.toBeNull();
            });
        });

        test("comments button", () => {
            waitForElement(() => {
                expect(queryByTestId(wrapper, "Leave-Cooment-text")).not.toBeNull();
            });
        });

    });

});
Example #22
Source File: MyRoutes.test.js    From viade_en1b with MIT License 5 votes vote down vote up
describe("Everything is rendered correctly", () => {
  test("routes are rendered", () => {
    waitForElement(() => {
      expect(queryByTestId(myRoutes, "myRoutes-route-list")).not.toBeNull();
      expect(queryByTestId(myRoutes, "myRoutes-route-details")).not.toBeNull();
    });
  });
});
Example #23
Source File: Slideshow.test.js    From viade_en1b with MIT License 5 votes vote down vote up
describe("The slideshow render correctly", () => {
  test("buttons are rendered when having some pictures to show", () => {
    waitForElement(() => {
      expect(queryByTestId(slideshowWithPictures, "previous")).not.toBeNull();
      expect(queryByTestId(slideshowWithPictures, "next")).not.toBeNull();
    });
  });

  test("buttons are not rendered when having no pictures to show", () => {
    waitForElement(() => {
      expect(queryByTestId(slideshowNoPictures, "previous")).toBeNull();
      expect(queryByTestId(slideshowNoPictures, "next")).toBeNull();
    });
  });

  test("images are rendered in the slideshow with pictures", () => {
    waitForElement(() => {
      expect(
        queryByTestId(slideshowWithPictures, "current-image-slideshow")
      ).not.toBeNull();
    });
  });

  test("images are not rendered in the slideshow with no pictures", () => {
    waitForElement(() => {
      expect(
        queryByTestId(slideshowNoPictures, "current-image-slideshow")
      ).toBeNull();
    });
  });

  test("buttons have the correct functionality", () => {
    waitForElement(() => {
      const nextButton = queryByTestId(slideshowWithPictures, "next");
      const previousButton = queryByTestId(slideshowWithPictures, "next");

      fireEvent.click(nextButton);
      expect(nextButton).toBeDisabled();

      fireEvent.click(previousButton);
      expect(previousButton).toBeDisabled();
    });
  });
});
Example #24
Source File: Modal.test.js    From viade_en1b with MIT License 5 votes vote down vote up
describe("All renders correctly with normal settings", () => {
  test("title is rendered", () => {
    fireEvent.click(queryByTestId(modal, "modalButton"));
    waitForDomChange(() => {
      expect(queryByTestId(modal, "modalTitle").textContent).not.toBeNull();
      expect(queryByTestId(modal, "modalTitle").textContent).toBe("Submitted");
    });
  });

  test("children are rendered", () => {
    let paragraph = <p>Hello there!</p>;
    rerenderFunc(
      <ViadeModal onOpen={mock} title="Submit">
        {paragraph}
      </ViadeModal>
    );
    waitForElement(() => {
      expect(paragraph).toBeInTheDocument();
    });
  });

  test("buttons are rendered", () => {
    fireEvent.click(queryByTestId(modal, "modalButton"));
    waitForDomChange(() => {
      expect(queryByTestId(modal, "modalSaveButton")).not.toBeNull();
      expect(queryByTestId(modal, "modalSaveButton")).toBe("Save");
      expect(queryByTestId(modal, "modalCloseButton")).not.toBeNull();
      expect(queryByTestId(modal, "modalCloseButton")).toBe("Close");
    });
  });

  test("on save function is triggered", () => {
    fireEvent.click(queryByTestId(modal, "modalButton"));
    waitForDomChange(() => {
      expect(queryByTestId(modal, "modalCloseButton")).not.toBeNull();
      expect(queryByTestId(modal, "modalCloseButton")).toBe("Close");
      expect(queryByTestId(modal, "modalSaveButton")).not.toBeNull();
      expect(queryByTestId(modal, "modalSaveButton")).toBe("Save");
      fireEvent.click(queryByTestId(modal, "modalSaveButton"));
      expect(mock).toBeCalled();
    });
  });
});
Example #25
Source File: NavBar.test.js    From viade_en1b with MIT License 5 votes vote down vote up
describe("Navbar is correctly rendered", () => {
  test("all buttons are rendered", () => {
    waitForElement(() => {
      expect(queryByTestId(rendered, "navbar-my-routes")).not.toBeNull();
      expect(queryByTestId(rendered, "navbar-upload-route")).not.toBeNull();
      expect(queryByTestId(rendered, "navbar-my-profile")).not.toBeNull();
      expect(queryByTestId(rendered, "navbar-logout")).not.toBeNull();
      expect(queryByTestId(rendered, "navbar-brand")).not.toBeNull();
      expect(queryByTestId(rendered, "navbar-settings")).not.toBeNull();
      expect(queryByTestId(rendered, "navbar-dashboard")).not.toBeNull();
      expect(queryByTestId(rendered, "navbar-notifications")).not.toBeNull();
      expect(queryByTestId(rendered, "navbar-groups")).not.toBeNull();
    });
  });

  test("redirections work", () => {
    waitForElement(() => {
      let routes = queryByTestId(rendered, "navbar-my-routes");
      let upload = queryByTestId(rendered, "navbar-upload-route");
      let profile = queryByTestId(rendered, "navbar-my-profile");
      let brand = queryByTestId(rendered, "navbar-brand");
      let logout = queryByTestId(rendered, "navbar-logout");
      let settings = queryByTestId(rendered, "navbar-settings");
      let dashboard = queryByTestId(rendered, "navbar-dashboard");
      let notifications = queryByTestId(rendered, "navbar-notifications");
      let groups = queryByTestId(rendered, "navbar-groups");

      fireEvent.click(groups);
      expect(getCurrentPage()).toEqual("groups");

      fireEvent.click(notifications);
      expect(getCurrentPage()).toEqual("notifications");

      fireEvent.click(routes);
      expect(getCurrentPage()).toEqual("routes");

      fireEvent.click(upload);
      expect(getCurrentPage()).toEqual("upload");

      fireEvent.click(profile);
      expect(getCurrentPage()).toEqual("profile");

      fireEvent.click(brand);
      expect(getCurrentPage()).toEqual("dashboard");

      fireEvent.click(logout);
      expect(getCurrentPage()).toEqual("");

      fireEvent.click(settings);
      expect(getCurrentPage()).toEqual("settings");

      fireEvent.click(dashboard);
      expect(getCurrentPage()).toEqual("dashboard");
    });
  });
});
Example #26
Source File: DiscussionsSettings.test.jsx    From frontend-app-course-authoring with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('DiscussionsSettings', () => {
  beforeEach(() => {
    initializeMockApp({
      authenticatedUser: {
        userId: 3,
        username: 'abc123',
        administrator: true,
        roles: [],
      },
    });

    store = initializeStore({
      models: {
        courseDetails: {
          [courseId]: {
            start: Date(),
          },
        },
      },
    });
    axiosMock = new MockAdapter(getAuthenticatedHttpClient());

    // Leave the DiscussionsSettings route after the test.
    history.push(`/course/${courseId}/pages-and-resources`);
  });

  describe('with successful network connections', () => {
    beforeEach(() => {
      axiosMock.onGet(getDiscussionsProvidersUrl(courseId))
        .reply(200, generateProvidersApiResponse(false));
      axiosMock.onGet(getDiscussionsSettingsUrl(courseId))
        .reply(200, generatePiazzaApiResponse(true));
      renderComponent();
    });

    test('sets selection step from routes', async () => {
      history.push(`/course/${courseId}/pages-and-resources/discussion`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      expect(queryByTestId(container, 'appList')).toBeInTheDocument();
      expect(queryByTestId(container, 'appConfigForm')).not.toBeInTheDocument();
    });

    test('sets settings step from routes', async () => {
      history.push(`/course/${courseId}/pages-and-resources/discussion/configure/piazza`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      expect(queryByTestId(container, 'appList')).not.toBeInTheDocument();
      expect(queryByTestId(container, 'appConfigForm')).toBeInTheDocument();
    });

    test('successfully advances to settings step for lti', async () => {
      history.push(`/course/${courseId}/pages-and-resources/discussion`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      userEvent.click(queryByLabelText(container, 'Select Piazza'));
      userEvent.click(queryByText(container, messages.nextButton.defaultMessage));

      await waitForElementToBeRemoved(screen.getByRole('status'));

      expect(queryByTestId(container, 'appList')).not.toBeInTheDocument();
      expect(queryByTestId(container, 'appConfigForm')).toBeInTheDocument();
      expect(queryByTestId(container, 'ltiConfigForm')).toBeInTheDocument();
      expect(queryByTestId(container, 'legacyConfigForm')).not.toBeInTheDocument();
    });

    test('successfully advances to settings step for legacy', async () => {
      axiosMock.onGet(getDiscussionsProvidersUrl(courseId)).reply(200, generateProvidersApiResponse(false, 'legacy'));
      axiosMock.onGet(getDiscussionsSettingsUrl(courseId)).reply(200, legacyApiResponse);
      renderComponent();
      history.push(`/course/${courseId}/pages-and-resources/discussion`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      userEvent.click(queryByLabelText(container, 'Select edX'));
      userEvent.click(queryByText(container, messages.nextButton.defaultMessage));

      await waitForElementToBeRemoved(screen.getByRole('status'));

      expect(queryByTestId(container, 'appList')).not.toBeInTheDocument();
      expect(queryByTestId(container, 'appConfigForm')).toBeInTheDocument();
      expect(queryByTestId(container, 'ltiConfigForm')).not.toBeInTheDocument();
      expect(queryByTestId(container, 'legacyConfigForm')).toBeInTheDocument();
    });

    test('successfully goes back to first step', async () => {
      history.push(`/course/${courseId}/pages-and-resources/discussion/configure/piazza`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      expect(queryByTestId(container, 'appConfigForm')).toBeInTheDocument();

      userEvent.click(queryByText(container, appMessages.backButton.defaultMessage));

      expect(queryByTestId(container, 'appList')).toBeInTheDocument();
      expect(queryByTestId(container, 'appConfigForm')).not.toBeInTheDocument();
    });

    test('successfully closes the modal', async () => {
      history.push(`/course/${courseId}/pages-and-resources/discussion`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      expect(queryByTestId(container, 'appList')).toBeInTheDocument();

      userEvent.click(queryByLabelText(container, 'Close'));

      expect(queryByTestId(container, 'appList')).not.toBeInTheDocument();
      expect(queryByTestId(container, 'appConfigForm')).not.toBeInTheDocument();

      expect(window.location.pathname).toEqual(`/course/${courseId}/pages-and-resources`);
    });

    test('successfully submit the modal', async () => {
      history.push(`/course/${courseId}/pages-and-resources/discussion`);

      axiosMock.onPost(getDiscussionsSettingsUrl(courseId)).reply(200, generatePiazzaApiResponse(true));

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      userEvent.click(queryByLabelText(container, 'Select Piazza'));

      userEvent.click(getByRole(container, 'button', { name: 'Next' }));

      userEvent.click(await findByRole(container, 'button', { name: 'Save' }));

      // This is an important line that ensures the Close button has been removed, which implies that
      // the full screen modal has been closed following our click of Apply.  Once this has happened,
      // then it's safe to proceed with our expectations.
      await waitForElementToBeRemoved(queryByRole(container, 'button', { name: 'Close' }));

      await waitFor(() => expect(window.location.pathname).toEqual(`/course/${courseId}/pages-and-resources`));
    });

    test('requires confirmation if changing provider', async () => {
      axiosMock.onGet(`${getConfig().LMS_BASE_URL}/api/courses/v1/courses/${courseId}?username=abc123`).reply(200, courseDetailResponse);
      await executeThunk(fetchCourseDetail(courseId), store.dispatch);
      history.push(`/course/${courseId}/pages-and-resources/discussion`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      userEvent.click(getByRole(container, 'checkbox', { name: 'Select Discourse' }));
      userEvent.click(getByRole(container, 'button', { name: 'Next' }));

      await findByRole(container, 'button', { name: 'Save' });
      userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Key' }), 'key');
      userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Secret' }), 'secret');
      userEvent.type(getByRole(container, 'textbox', { name: 'Launch URL' }), 'http://example.test');
      userEvent.click(getByRole(container, 'button', { name: 'Save' }));

      await waitFor(() => expect(getByRole(container, 'dialog', { name: 'OK' })).toBeInTheDocument());
    });

    test('can cancel confirmation', async () => {
      axiosMock.onGet(`${getConfig().LMS_BASE_URL}/api/courses/v1/courses/${courseId}?username=abc123`).reply(200, courseDetailResponse);
      await executeThunk(fetchCourseDetail(courseId), store.dispatch);
      history.push(`/course/${courseId}/pages-and-resources/discussion`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      const discourseBox = getByRole(container, 'checkbox', { name: 'Select Discourse' });
      expect(discourseBox).not.toBeDisabled();
      userEvent.click(discourseBox);

      userEvent.click(getByRole(container, 'button', { name: 'Next' }));
      await waitForElementToBeRemoved(screen.getByRole('status'));
      expect(getByRole(container, 'heading', { name: 'Discourse' })).toBeInTheDocument();

      userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Key' }), 'a');
      userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Secret' }), 'secret');
      userEvent.type(getByRole(container, 'textbox', { name: 'Launch URL' }), 'http://example.test');
      userEvent.click(getByRole(container, 'button', { name: 'Save' }));

      await waitFor(() => expect(getByRole(container, 'dialog', { name: 'OK' })).toBeInTheDocument());
      userEvent.click(getByRole(container, 'button', { name: 'Cancel' }));

      expect(queryByRole(container, 'dialog', { name: 'Confirm' })).not.toBeInTheDocument();
      expect(queryByRole(container, 'dialog', { name: 'Configure discussion' }));
    });
  });

  describe('with network error fetchProviders API requests', () => {
    beforeEach(() => {
      // Expedient way of getting SUPPORT_URL into config.
      setConfig({
        ...getConfig(),
        SUPPORT_URL: 'http://support.edx.org',
      });

      axiosMock.onGet(getDiscussionsProvidersUrl(courseId)).networkError();
      axiosMock.onGet(getDiscussionsSettingsUrl(courseId)).networkError();
      renderComponent();
    });

    test('shows connection error alert', async () => {
      history.push(`/course/${courseId}/pages-and-resources/discussion`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      const alert = queryByRole(container, 'alert');
      expect(alert).toBeInTheDocument();
      expect(alert.textContent).toEqual(expect.stringContaining('We encountered a technical error when loading this page.'));
      expect(alert.innerHTML).toEqual(expect.stringContaining(getConfig().SUPPORT_URL));
    });
  });

  describe('with network error postAppConfig API requests', () => {
    beforeEach(() => {
      // Expedient way of getting SUPPORT_URL into config.
      setConfig({
        ...getConfig(),
        SUPPORT_URL: 'http://support.edx.org',
      });

      axiosMock.onGet(getDiscussionsProvidersUrl(courseId))
        .reply(200, generateProvidersApiResponse());
      axiosMock.onGet(getDiscussionsSettingsUrl(courseId))
        .reply(200, piazzaApiResponse);
      axiosMock.onPost(getDiscussionsSettingsUrl(courseId)).networkError();
      renderComponent();
    });

    test('shows connection error alert at top of form', async () => {
      history.push(`/course/${courseId}/pages-and-resources/discussion/configure/piazza`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      // Apply causes an async action to take place
      act(() => {
        userEvent.click(queryByText(container, appMessages.saveButton.defaultMessage));
      });

      await waitFor(() => expect(axiosMock.history.post.length).toBe(1));

      expect(queryByTestId(container, 'appConfigForm')).toBeInTheDocument();
      const alert = await findByRole(container, 'alert');
      expect(alert).toBeInTheDocument();
      expect(alert.textContent).toEqual(expect.stringContaining('We encountered a technical error when applying changes.'));
      expect(alert.innerHTML).toEqual(expect.stringContaining(getConfig().SUPPORT_URL));
    });
  });

  describe('with permission denied error for fetchProviders API requests', () => {
    beforeEach(() => {
      axiosMock.onGet(getDiscussionsProvidersUrl(courseId)).reply(403);
      axiosMock.onGet(getDiscussionsSettingsUrl(courseId)).reply(403);

      renderComponent();
    });

    test('shows permission denied alert', async () => {
      history.push(`/course/${courseId}/pages-and-resources/discussion`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      const alert = queryByRole(container, 'alert');
      expect(alert).toBeInTheDocument();
      expect(alert.textContent).toEqual(expect.stringContaining('You are not authorized to view this page.'));
    });
  });

  describe('with permission denied error for postAppConfig API requests', () => {
    beforeEach(() => {
      axiosMock.onGet(getDiscussionsProvidersUrl(courseId))
        .reply(200, generateProvidersApiResponse());
      axiosMock.onGet(getDiscussionsSettingsUrl(courseId)).reply(200, piazzaApiResponse);
      axiosMock.onPost(getDiscussionsSettingsUrl(courseId)).reply(403);

      renderComponent();
    });

    test('shows permission denied alert at top of form', async () => {
      history.push(`/course/${courseId}/pages-and-resources/discussion/configure/piazza`);

      // This is an important line that ensures the spinner has been removed - and thus our main
      // content has been loaded - prior to proceeding with our expectations.
      await waitForElementToBeRemoved(screen.getByRole('status'));

      userEvent.click(getByRole(container, 'button', { name: 'Save' }));

      await waitFor(() => expect(axiosMock.history.post.length).toBe(1));

      expect(queryByTestId(container, 'appList')).not.toBeInTheDocument();
      expect(queryByTestId(container, 'appConfigForm')).not.toBeInTheDocument();

      // We don't technically leave the route in this case, though the modal is hidden.
      expect(window.location.pathname).toEqual(`/course/${courseId}/pages-and-resources/discussion/configure/piazza`);

      const alert = await findByRole(container, 'alert');
      expect(alert).toBeInTheDocument();
      expect(alert.textContent).toEqual(expect.stringContaining('You are not authorized to view this page.'));
    });
  });
});
Example #27
Source File: OpenedXConfigForm.test.jsx    From frontend-app-course-authoring with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('OpenedXConfigForm', () => {
  let axiosMock;
  let store;
  let container;

  beforeEach(async () => {
    initializeMockApp({
      authenticatedUser: {
        userId: 3,
        username: 'abc123',
        administrator: true,
        roles: [],
      },
    });
    axiosMock = new MockAdapter(getAuthenticatedHttpClient());
    store = initializeStore();
  });

  afterEach(() => {
    axiosMock.reset();
  });

  const createComponent = (onSubmit = jest.fn(), formRef = createRef(), legacy = true) => {
    const wrapper = render(
      <AppProvider store={store}>
        <IntlProvider locale="en">
          <OpenedXConfigForm
            onSubmit={onSubmit}
            formRef={formRef}
            legacy={legacy}
          />
        </IntlProvider>
      </AppProvider>,
    );
    container = wrapper.container;
    return container;
  };

  const mockStore = async (mockResponse) => {
    axiosMock.onGet(getDiscussionsProvidersUrl(courseId)).reply(200, generateProvidersApiResponse());
    axiosMock.onGet(getDiscussionsSettingsUrl(courseId)).reply(200, mockResponse);
    await executeThunk(fetchProviders(courseId), store.dispatch);
    await executeThunk(fetchDiscussionSettings(courseId), store.dispatch);
    store.dispatch(selectApp({ appId: 'legacy' }));
  };

  test('title rendering', async () => {
    await mockStore(legacyApiResponse);
    createComponent();
    expect(container.querySelector('h3')).toHaveTextContent('edX');
  });

  test('new Open edX provider config', async () => {
    await mockStore({ ...legacyApiResponse, enable_in_context: true });
    createComponent(jest.fn(), createRef(), false);
    expect(queryByText(container, messages.visibilityInContext.defaultMessage)).toBeInTheDocument();
    expect(queryByText(container, messages.gradedUnitPagesLabel.defaultMessage)).toBeInTheDocument();
    expect(queryByText(container, messages.groupInContextSubsectionLabel.defaultMessage)).toBeInTheDocument();
    expect(queryByText(container, messages.allowUnitLevelVisibilityLabel.defaultMessage)).toBeInTheDocument();
  });

  test('calls onSubmit when the formRef is submitted', async () => {
    const formRef = createRef();
    const handleSubmit = jest.fn();

    await mockStore(legacyApiResponse);
    createComponent(handleSubmit, formRef);

    await act(async () => {
      formRef.current.submit();
    });

    expect(handleSubmit).toHaveBeenCalledWith(
      // Because we use defaultAppConfig as the initialValues of the form, and we haven't changed
      // any of the form inputs, this exact object shape is returned back to us, so we're reusing
      // it here.  It's not supposed to be 'the same object', it just happens to be.
      {
        ...defaultAppConfig(),
        divideByCohorts: false,
        divisionScheme: DivisionSchemes.COHORT,
      },
    );
  });

  test('default field states are correct, including removal of folded sub-fields', async () => {
    await mockStore({
      ...legacyApiResponse,
      plugin_configuration: {
         ...legacyApiResponse.plugin_configuration,
        reported_content_email_notifications_flag: true,
        divided_course_wide_discussions: [],
      },
    });
    createComponent();
    const { divideDiscussionIds } = defaultAppConfig(['13f106c6-6735-4e84-b097-0456cff55960', 'course']);

    // DivisionByGroupFields
    expect(container.querySelector('#divideByCohorts')).toBeInTheDocument();
    expect(container.querySelector('#divideByCohorts')).not.toBeChecked();
    expect(container.querySelector('#divideCourseTopicsByCohorts')).not.toBeInTheDocument();

    divideDiscussionIds.forEach(id => expect(
      container.querySelector(`#checkbox-${id}`),
    ).not.toBeInTheDocument());

    // AnonymousPostingFields
    expect(
      container.querySelector('#allowAnonymousPostsPeers'),
    ).toBeInTheDocument();
    expect(container.querySelector('#allowAnonymousPostsPeers')).not.toBeChecked();

    // ReportedContentEmailNotifications
    expect(container.querySelector('#reportedContentEmailNotifications')).toBeInTheDocument();
    expect(container.querySelector('#reportedContentEmailNotifications')).not.toBeChecked();

    // BlackoutDatesField
    expect(queryByText(container, messages.blackoutDatesLabel.defaultMessage)).toBeInTheDocument();
  });

  test('folded sub-fields are in the DOM when parents are enabled', async () => {
    await mockStore({
      ...legacyApiResponse,
      plugin_configuration: {
        ...legacyApiResponse.plugin_configuration,
        allow_anonymous: true,
        reported_content_email_notifications: true,
        reported_content_email_notifications_flag: true,
        always_divide_inline_discussions: true,
        divided_course_wide_discussions: [],
      },
    });
    createComponent();
    const { divideDiscussionIds } = defaultAppConfig(['13f106c6-6735-4e84-b097-0456cff55960', 'course']);

    // DivisionByGroupFields
    expect(container.querySelector('#divideByCohorts')).toBeInTheDocument();
    expect(container.querySelector('#divideByCohorts')).toBeChecked();
    expect(
      container.querySelector('#divideCourseTopicsByCohorts'),
    ).toBeInTheDocument();
    expect(
      container.querySelector('#divideCourseTopicsByCohorts'),
    ).not.toBeChecked();

    divideDiscussionIds.forEach(id => expect(
      container.querySelector(`#checkbox-${id}`),
    ).not.toBeInTheDocument());

    // AnonymousPostingFields
    expect(
      container.querySelector('#allowAnonymousPostsPeers'),
    ).toBeInTheDocument();
    expect(
      container.querySelector('#allowAnonymousPostsPeers'),
    ).not.toBeChecked();

    // ReportedContentEmailNotifications
    expect(container.querySelector('#reportedContentEmailNotifications')).toBeInTheDocument();
    expect(container.querySelector('#reportedContentEmailNotifications')).toBeChecked();
  });

  test('folded discussion topics are in the DOM when divideByCohorts and divideCourseWideTopics are enabled',
    async () => {
      await mockStore({
        ...legacyApiResponse,
        plugin_configuration: {
          ...legacyApiResponse.plugin_configuration,
          allow_anonymous: true,
          reported_content_email_notifications: true,
          reported_content_email_notifications_flag: true,
          always_divide_inline_discussions: true,
          divided_course_wide_discussions: ['13f106c6-6735-4e84-b097-0456cff55960', 'course'],
        },
      });
      createComponent();
      const { divideDiscussionIds } = defaultAppConfig(['13f106c6-6735-4e84-b097-0456cff55960', 'course']);

      // DivisionByGroupFields
      expect(container.querySelector('#divideByCohorts')).toBeInTheDocument();
      expect(container.querySelector('#divideByCohorts')).toBeChecked();
      expect(container.querySelector('#divideCourseTopicsByCohorts')).toBeInTheDocument();
      expect(container.querySelector('#divideCourseTopicsByCohorts')).toBeChecked();

      divideDiscussionIds.forEach(id => {
        expect(container.querySelector(`#checkbox-${id}`)).toBeInTheDocument();
        expect(container.querySelector(`#checkbox-${id}`)).toBeChecked();
      });
    });

  const updateTopicName = async (topicId, topicName) => {
    const topicCard = queryByTestId(container, topicId);

    await act(async () => { userEvent.click(queryByLabelText(topicCard, 'Expand')); });
    const topicInput = topicCard.querySelector('input');
    topicInput.focus();
    await act(async () => { fireEvent.change(topicInput, { target: { value: topicName } }); });
    topicInput.blur();

    return topicCard;
  };

  const assertTopicNameRequiredValidation = (topicCard, expectExists = true) => {
    const error = queryByText(topicCard, messages.discussionTopicRequired.defaultMessage);
    if (expectExists) { expect(error).toBeInTheDocument(); } else { expect(error).not.toBeInTheDocument(); }
  };

  const assertDuplicateTopicNameValidation = async (topicCard, expectExists = true) => {
    const error = queryByText(topicCard, messages.discussionTopicNameAlreadyExist.defaultMessage);
    if (expectExists) { expect(error).toBeInTheDocument(); } else { expect(error).not.toBeInTheDocument(); }
  };

  const assertHasErrorValidation = (expectExists = true) => {
    expect(store.getState().discussions.hasValidationError).toBe(expectExists);
  };

  test('show required error on field when leaving empty topic name',
    async () => {
      await mockStore(legacyApiResponse);
      createComponent();

      const topicCard = await updateTopicName('13f106c6-6735-4e84-b097-0456cff55960', '');
      await waitForElementToBeRemoved(queryByText(topicCard, messages.addTopicHelpText.defaultMessage));
      assertTopicNameRequiredValidation(topicCard);
      assertHasErrorValidation();
    });

  test('check field is not collapsible in case of error', async () => {
    await mockStore(legacyApiResponse);
    createComponent();

    const topicCard = await updateTopicName('13f106c6-6735-4e84-b097-0456cff55960', '');
    const collapseButton = queryByLabelText(topicCard, 'Collapse');
    await act(async () => userEvent.click(collapseButton));

    expect(collapseButton).toBeInTheDocument();
  });

  describe('Duplicate validation test cases', () => {
    let topicCard;
    let duplicateTopicCard;

    beforeEach(async () => {
      await mockStore(legacyApiResponse);
      createComponent();

      topicCard = await updateTopicName('course', 'edx');
      duplicateTopicCard = await updateTopicName('13f106c6-6735-4e84-b097-0456cff55960', 'EDX');
    });

    test('show duplicate errors on fields when passing duplicate topic name', async () => {
      await assertDuplicateTopicNameValidation(topicCard);
      await assertDuplicateTopicNameValidation(duplicateTopicCard);
      assertHasErrorValidation();
    });

    test('check duplicate error is removed on fields when name is fixed', async () => {
      const duplicateTopicInput = duplicateTopicCard.querySelector('input');
      duplicateTopicInput.focus();
      await act(async () => { userEvent.type(duplicateTopicInput, 'valid'); });
      duplicateTopicInput.blur();

      await waitForElementToBeRemoved(
        queryAllByText(topicCard, messages.discussionTopicNameAlreadyExist.defaultMessage),
      );

      await assertDuplicateTopicNameValidation(duplicateTopicCard, false);
      await assertDuplicateTopicNameValidation(topicCard, false);
      assertHasErrorValidation(false);
    });

    test('check duplicate error is removed on deleting duplicate topic', async () => {
      await act(async () => {
        userEvent.click(
          queryByLabelText(duplicateTopicCard, messages.deleteAltText.defaultMessage, { selector: 'button' }),
        );
      });

      await act(async () => {
        userEvent.click(
          queryByRole(container, 'button', { name: messages.deleteButton.defaultMessage }),
        );
      });

      await waitForElementToBeRemoved(queryByText(topicCard, messages.discussionTopicNameAlreadyExist.defaultMessage));

      expect(duplicateTopicCard).not.toBeInTheDocument();
      await assertDuplicateTopicNameValidation(topicCard, false);
      assertHasErrorValidation(false);
    });
  });
});
Example #28
Source File: DiscussionTopics.test.jsx    From frontend-app-course-authoring with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('DiscussionTopics', () => {
  let axiosMock;
  let store;
  let container;
  beforeEach(() => {
    initializeMockApp({
      authenticatedUser: {
        userId: 3,
        username: 'abc123',
        administrator: true,
        roles: [],
      },
    });

    axiosMock = new MockAdapter(getAuthenticatedHttpClient());
    store = initializeStore();
  });

  afterEach(() => {
    axiosMock.reset();
  });

  const createComponent = (data) => {
    const wrapper = render(
      <AppProvider store={store}>
        <IntlProvider locale="en">
          <OpenedXConfigFormProvider value={contextValue}>
            <Formik initialValues={data}>
              <DiscussionTopics />
            </Formik>
          </OpenedXConfigFormProvider>
        </IntlProvider>
      </AppProvider>,
    );
    container = wrapper.container;
  };

  const mockStore = async (mockResponse) => {
    axiosMock.onGet(getDiscussionsProvidersUrl(courseId)).reply(200, mockResponse);
    await executeThunk(fetchProviders(courseId), store.dispatch);
  };

  test('renders each discussion topic correctly', async () => {
    await mockStore(legacyApiResponse);
    createComponent(appConfig);
    await waitFor(() => {
      expect(queryAllByTestId(container, 'course')).toHaveLength(1);
      expect(queryAllByTestId(container, '13f106c6-6735-4e84-b097-0456cff55960')).toHaveLength(1);
    });
  });

  test('renders discussion topic heading, label and helping text', async () => {
    await mockStore(legacyApiResponse);
    createComponent(appConfig);
    await waitFor(() => {
      expect(queryByText(container, messages.discussionTopics.defaultMessage)).toBeInTheDocument();
      expect(queryByText(container, messages.discussionTopicsLabel.defaultMessage)).toBeInTheDocument();
      expect(queryByText(container, messages.discussionTopicsHelp.defaultMessage)).toBeInTheDocument();
    });
  });

  test('add topic button is rendered correctly', async () => {
    await mockStore(legacyApiResponse);
    createComponent(appConfig);
    await waitFor(() => {
      expect(queryByText(container, messages.addTopicButton.defaultMessage, { selector: 'button' }))
        .toBeInTheDocument();
    });
  });

  test('calls "onClick" callback when add topic button is clicked', async () => {
    await mockStore(legacyApiResponse);
    createComponent(appConfig);

    const addTopicButton = queryByText(container, messages.addTopicButton.defaultMessage, { selector: 'button' });
    await waitFor(async () => {
      expect(queryByText(container, messages.configureAdditionalTopic.defaultMessage)).not.toBeInTheDocument();
      await act(async () => fireEvent.click(addTopicButton));
      expect(queryByText(container, messages.configureAdditionalTopic.defaultMessage)).toBeInTheDocument();
    });
  });

  test('updates discussion topic name', async () => {
    await mockStore(legacyApiResponse);
    createComponent(appConfig);
    const topicCard = queryByTestId(container, '13f106c6-6735-4e84-b097-0456cff55960');

    await act(async () => userEvent.click(queryByLabelText(topicCard, 'Expand')));
    await act(async () => {
      fireEvent.change(topicCard.querySelector('input'), { target: { value: 'new name' } });
    });
    await act(async () => userEvent.click(queryByLabelText(topicCard, 'Collapse')));

    expect(queryByText(topicCard, 'new name')).toBeInTheDocument();
  });
});
Example #29
Source File: TopicItem.test.jsx    From frontend-app-course-authoring with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('TopicItem', () => {
  let axiosMock;
  let store;
  let container;

  beforeEach(() => {
    initializeMockApp({
      authenticatedUser: {
        userId: 3,
        username: 'abc123',
        administrator: true,
        roles: [],
      },
    });

    axiosMock = new MockAdapter(getAuthenticatedHttpClient());
    store = initializeStore();
  });

  afterEach(() => {
    axiosMock.reset();
  });

  const createComponent = (props) => {
    const wrapper = render(
      <AppProvider store={store}>
        <IntlProvider locale="en">
          <Formik initialValues={appConfig}>
            <TopicItem {...props} />
          </Formik>
        </IntlProvider>
      </AppProvider>,
    );
    container = wrapper.container;
  };

  const mockStore = async (mockResponse) => {
    axiosMock.onGet(getDiscussionsProvidersUrl(courseId)).reply(200, mockResponse);
    await executeThunk(fetchProviders(courseId), store.dispatch);
  };

  test('displays a collapsible card for discussion topic', async () => {
    await mockStore(legacyApiResponse);
    createComponent(generalTopic);

    expect(queryAllByTestId(container, 'course')).toHaveLength(1);
  });

  test('displays collapse view of general discussion topic', async () => {
    await mockStore(legacyApiResponse);
    createComponent(generalTopic);

    const generalTopicNode = queryByTestId(container, 'course');
    expect(queryByLabelText(generalTopicNode, 'Expand')).toBeInTheDocument();
    expect(queryByLabelText(generalTopicNode, 'Collapse')).not.toBeInTheDocument();
    expect(queryByText(generalTopicNode, 'General')).toBeInTheDocument();
  });

  test('displays expand view of general discussion topic', async () => {
    await mockStore(legacyApiResponse);
    createComponent(generalTopic);

    const generalTopicNode = queryByTestId(container, 'course');
    userEvent.click(queryByLabelText(generalTopicNode, 'Expand'));

    expect(queryByLabelText(generalTopicNode, 'Expand')).not.toBeInTheDocument();
    expect(queryByLabelText(generalTopicNode, 'Collapse')).toBeInTheDocument();
    expect(queryByRole(generalTopicNode, 'button', { name: 'Delete Topic' })).not.toBeInTheDocument();
    expect(generalTopicNode.querySelector('input')).toBeInTheDocument();
  });

  test('displays expand view of additional discussion topic', async () => {
    await mockStore(legacyApiResponse);
    createComponent(additionalTopic);

    const topicCard = queryByTestId(container, '13f106c6-6735-4e84-b097-0456cff55960');
    userEvent.click(queryByLabelText(topicCard, 'Expand'));

    expect(queryByLabelText(topicCard, 'Expand')).not.toBeInTheDocument();
    expect(queryByLabelText(topicCard, 'Collapse')).toBeInTheDocument();
    expect(queryByRole(topicCard, 'button', { name: 'Delete Topic' })).toBeInTheDocument();
    expect(topicCard.querySelector('input')).toBeInTheDocument();
  });

  test('renders delete topic popup with providerName, label, helping text, a delete and a cancel button', async () => {
    await mockStore(legacyApiResponse);
    createComponent(additionalTopic);

    const topicCard = queryByTestId(container, '13f106c6-6735-4e84-b097-0456cff55960');
    userEvent.click(queryByLabelText(topicCard, 'Expand'));
    userEvent.click(queryByRole(topicCard, 'button', { name: 'Delete Topic' }));

    expect(queryAllByText(container, messages.discussionTopicDeletionLabel.defaultMessage)).toHaveLength(1);
    expect(queryByText(container, messages.discussionTopicDeletionLabel.defaultMessage)).toBeInTheDocument();
    expect(queryByText(container, messages.discussionTopicDeletionHelp.defaultMessage)).toBeInTheDocument();
    expect(queryByText(container, messages.discussionTopicDeletionHelp.defaultMessage)).toBeInTheDocument();
    expect(queryByText(container, messages.deleteButton.defaultMessage)).toBeInTheDocument();
    expect(queryByText(container, messages.cancelButton.defaultMessage)).toBeInTheDocument();
  });

  test('shows help text on field focus', async () => {
    await mockStore(legacyApiResponse);
    createComponent(additionalTopic);

    const topicCard = queryByTestId(container, '13f106c6-6735-4e84-b097-0456cff55960');
    userEvent.click(queryByLabelText(topicCard, 'Expand'));
    topicCard.querySelector('input').focus();

    expect(queryByText(topicCard, messages.addTopicHelpText.defaultMessage)).toBeInTheDocument();
  });
});