tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ReportContent.test.jsx (7369B)


      1 import { mount } from "enzyme";
      2 import { INITIAL_STATE, reducers } from "common/Reducers.sys.mjs";
      3 import { ReportContent } from "content-src/components/DiscoveryStreamComponents/ReportContent/ReportContent";
      4 import { combineReducers, createStore } from "redux";
      5 import { Provider } from "react-redux";
      6 import { actionCreators as ac } from "common/Actions.mjs";
      7 import React from "react";
      8 
      9 const DEFAULT_PROPS = {
     10  dispatch() {},
     11  prefs: {
     12    ...INITIAL_STATE.Prefs,
     13    values: {
     14      ...INITIAL_STATE.Prefs.values,
     15      "discoverystream.sections.enabled": true,
     16      "unifiedAds.spocs.enabled": true,
     17    },
     18  },
     19 };
     20 
     21 const BASE_REPORT = {
     22  visible: true,
     23  url: "https://example.com",
     24  position: 1,
     25  reporting_url: "https://example.com/report",
     26 };
     27 
     28 function testState({ card_type, visible }) {
     29  return {
     30    Prefs: DEFAULT_PROPS.prefs,
     31    DiscoveryStream: {
     32      ...INITIAL_STATE.DiscoveryStream,
     33      report: {
     34        ...BASE_REPORT,
     35        card_type,
     36        visible,
     37      },
     38    },
     39  };
     40 }
     41 
     42 // Wrap this around any component that uses useSelector,
     43 // or any mount that uses a child that uses redux.
     44 function WrapWithProvider({ children, state, dispatch }) {
     45  let store = createStore(combineReducers(reducers), state);
     46  if (dispatch) {
     47    store.dispatch = dispatch;
     48  }
     49  return <Provider store={store}>{children}</Provider>;
     50 }
     51 
     52 // patch dialog element's .showModal()/close() functions to prevent errors in tests
     53 before(() => {
     54  if (typeof HTMLDialogElement !== "undefined") {
     55    HTMLDialogElement.prototype.showModal = function () {
     56      this.open = true;
     57    };
     58    HTMLDialogElement.prototype.close = function () {
     59      this.open = false;
     60    };
     61  }
     62 });
     63 
     64 describe("Discovery Stream <ReportContent>", () => {
     65  let wrapper;
     66  let sandbox;
     67  let dispatch;
     68 
     69  beforeEach(() => {
     70    sandbox = sinon.createSandbox();
     71    dispatch = sandbox.stub();
     72 
     73    wrapper = mount(
     74      <WrapWithProvider>
     75        <ReportContent
     76          dispatch={dispatch}
     77          {...DEFAULT_PROPS}
     78          spocs={{ spocs: { data: {} } }}
     79        />
     80      </WrapWithProvider>
     81    );
     82  });
     83 
     84  afterEach(() => {
     85    sandbox.restore();
     86  });
     87 
     88  it("should render", () => {
     89    assert.ok(wrapper.exists());
     90    assert.ok(wrapper.find(".report-content-form").exists());
     91  });
     92 
     93  it("should open modal if report.visible is true", () => {
     94    const state = testState({ visible: true });
     95 
     96    wrapper = mount(
     97      <WrapWithProvider state={state}>
     98        <ReportContent spocs={{ spocs: { data: {} } }} />
     99      </WrapWithProvider>
    100    );
    101    assert.ok(wrapper.find("dialog").getDOMNode().open);
    102  });
    103 
    104  it("should close modal if report.visible is false", () => {
    105    const state = testState({ visible: false });
    106 
    107    wrapper = mount(
    108      <WrapWithProvider state={state}>
    109        <ReportContent spocs={{ spocs: { data: {} } }} />
    110      </WrapWithProvider>
    111    );
    112 
    113    assert.equal(wrapper.find("dialog").getDOMNode().open, false);
    114  });
    115 
    116  it("should render ad reporting options if card_type is spoc", () => {
    117    const state = testState({ card_type: "spoc" });
    118 
    119    // in the ReportContent.jsx file, spocs.spocs.data is used to grab spoc data
    120    wrapper = mount(
    121      <WrapWithProvider state={state}>
    122        <ReportContent spocs={{ spocs: { data: {} } }} />
    123      </WrapWithProvider>
    124    );
    125 
    126    assert.ok(wrapper.find(".report-ads-options").exists());
    127 
    128    // test to make sure content options aren't displayed when report ads is open
    129    assert.equal(wrapper.find(".report-content-options").length, 0);
    130  });
    131 
    132  it("should render content reporting options if card_type is organic", () => {
    133    const state = testState({ card_type: "organic" });
    134 
    135    // in the ReportContent.jsx file, spocs.spocs.data is used to grab spoc data
    136    wrapper = mount(
    137      <WrapWithProvider state={state}>
    138        <ReportContent spocs={{}} />
    139      </WrapWithProvider>
    140    );
    141 
    142    assert.ok(wrapper.find(".report-content-options").exists());
    143 
    144    // test to make sure ad options aren't displayed when report content is open
    145    assert.equal(wrapper.find(".report-ads-options").length, 0);
    146  });
    147 
    148  it("should dispatch REPORT_CLOSE when cancel button is clicked", () => {
    149    const state = testState({ visible: true });
    150 
    151    wrapper = mount(
    152      <WrapWithProvider state={state} dispatch={dispatch}>
    153        <ReportContent spocs={{}} />
    154      </WrapWithProvider>
    155    );
    156 
    157    // Cancel button implementation
    158    const cancelButton = wrapper.find("moz-button.cancel-report-btn");
    159    assert.ok(cancelButton.exists());
    160    cancelButton.simulate("click");
    161 
    162    assert.calledOnce(dispatch);
    163 
    164    const call = dispatch.getCall(0);
    165    assert.deepEqual(
    166      call.args[0],
    167      ac.AlsoToMain({
    168        type: "REPORT_CLOSE",
    169      })
    170    );
    171  });
    172 
    173  it("should dispatch REPORT_CONTENT_SUBMIT, BLOCK_URL, and SHOW_TOAST_MESSAGE when submit button is clicked", () => {
    174    const state = testState({ visible: true, card_type: "organic" });
    175 
    176    wrapper = mount(
    177      <WrapWithProvider state={state} dispatch={dispatch}>
    178        <ReportContent spocs={{}} />
    179      </WrapWithProvider>
    180    );
    181 
    182    // Submit button implementation
    183    const submitButton = wrapper.find("moz-button.submit-report-btn");
    184    assert.ok(submitButton.exists());
    185    submitButton.simulate("click");
    186 
    187    // Assert both action types were dispatched
    188    assert.calledThrice(dispatch);
    189 
    190    const firstCall = dispatch.getCall(0);
    191    const secondCall = dispatch.getCall(1);
    192    const thirdCall = dispatch.getCall(2);
    193 
    194    // Using .match instead of .deepEqual because submitting a report passes a lot of data during dispatch. And using .match makes it so we don't have to write out all the data
    195    assert.match(
    196      firstCall.args[0],
    197      ac.AlsoToMain({
    198        type: "REPORT_CONTENT_SUBMIT",
    199      })
    200    );
    201 
    202    assert.match(
    203      secondCall.args[0],
    204      ac.AlsoToMain({
    205        type: "BLOCK_URL",
    206      })
    207    );
    208 
    209    assert.match(
    210      thirdCall.args[0],
    211      ac.OnlyToOneContent(
    212        {
    213          type: "SHOW_TOAST_MESSAGE",
    214        },
    215        "ActivityStream:Content"
    216      )
    217    );
    218  });
    219 
    220  it("should clear selected radio button when modal closes", () => {
    221    // Initial render with modal visible
    222    const openState = testState({ visible: true });
    223 
    224    wrapper = mount(
    225      <WrapWithProvider state={openState} dispatch={dispatch}>
    226        <ReportContent spocs={{ spocs: {} }} />
    227      </WrapWithProvider>
    228    );
    229 
    230    // Select the first radio button
    231    const radioGroup = wrapper.find("moz-radio-group").getDOMNode();
    232    const firstRadio = radioGroup.querySelector("moz-radio");
    233 
    234    firstRadio.setAttribute("checked", "true");
    235 
    236    // Assert it's checked before modal closes
    237    assert.equal(firstRadio.hasAttribute("checked"), true);
    238 
    239    // Simulate closing the modal to clear the radio button
    240    const closedState = testState({ visible: false });
    241 
    242    wrapper = mount(
    243      <WrapWithProvider state={closedState} dispatch={dispatch}>
    244        <ReportContent spocs={{ spocs: {} }} />
    245      </WrapWithProvider>
    246    );
    247 
    248    const updatedRadioGroup = wrapper.find("moz-radio-group").getDOMNode();
    249    const updatedFirstRadio = updatedRadioGroup.querySelector("moz-radio");
    250 
    251    // The previously checked radio should now be unchecked
    252    assert.equal(
    253      updatedFirstRadio.hasAttribute("checked"),
    254      false,
    255      "Radio button should be unchecked after modal closes"
    256    );
    257  });
    258 });