NMF-earth / nmf-app

Understand and reduce your carbon footprint 🌱 iOS & Android.
https://nmf.earth
GNU General Public License v3.0
487 stars 156 forks source link

Add ui/unit tests to BarCodeScanScreen NotificationsScreen #367

Open PierreBresson opened 1 year ago

PierreBresson commented 1 year ago

Describe the bug Tests are failing on main branch, see 366 and https://github.com/NMF-earth/nmf-app/actions/runs/4446824624 Find it why this was not catch on CI and fix Github Actions

saurabhchatterjee23 commented 8 months ago

Git action CI test is failing for quite some time

Test Suites: 68 passed, 68 total
Tests:       435 passed, 435 total
Snapshots:   145 passed, 145 total
Time:        120.703 s
Ran all test suites.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

https://github.com/NMF-earth/nmf-app/actions/workflows/test.yml

PierreBresson commented 8 months ago

Indeed, the CI is failing for quite some time and I haven't figured why. The tests/snapshots passed/total numbers are identical

saurabhchatterjee23 commented 8 months ago

The CI is failing even when all tests are succeeding because 2 tests are logging errors on the console.

I was able to disable these tests in my forked repo which lead the CI to succeed https://github.com/saurabhchatterjee23/nmf-app/actions/runs/6753966624/job/18360988524

The tests are failing with the same error

BarCodeScanScreen

  ●  Cannot log after tests are done. Did you forget to wait for something async in your test?
    Attempted to log "Warning: An update to BarCodeScanScreen inside a test was not wrapped in act(...).

    When testing, code that causes React state updates should be wrapped into act(...):

    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */

    This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
        at BarCodeScanScreen (/Users/mac/workspace/nmf-app/app/screens/BarCodeScan/BarCodeScanScreen.tsx:31:28)
        at _class (/Users/mac/workspace/nmf-app/app/utils/translations/localization.tsx:31:36)".

      29 |   const [hasCarbonData, setHasCarbonData] = useState(true);
      30 |   const [isFetchingData, setIsFetchingData] = useState(false);
    > 31 |   const [error, setError] = useState(false);
         |                            ^
      32 |   const [nutriscoreGrade, setNutriscoreGrade] = useState("");
      33 |   const [novaGroup, setNovaGroup] = useState(0);
      34 |   const [ecoScore, setEcoScore] = useState("");

      at BarCodeScanScreen (app/screens/BarCodeScan/BarCodeScanScreen.tsx:31:28)
      at _class (app/utils/translations/localization.tsx:31:36)".
      at console.error (node_modules/@jest/console/build/BufferedConsole.js:127:10)
      at printWarning (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:72:30)
      at error (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:46:7)
      at warnIfUpdatesNotWrappedWithActDEV (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:16677:9)
      at scheduleUpdateOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14877:5)
      at dispatchSetState (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7510:7)
      at app/screens/BarCodeScan/BarCodeScanScreen.tsx:77:7
      at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
      at _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)

NotificationsScreen

 ●  Cannot log after tests are done. Did you forget to wait for something async in your test?
    Attempted to log "Warning: An update to NotificationsScreen inside a test was not wrapped in act(...).

    When testing, code that causes React state updates should be wrapped into act(...):

    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */

    This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
        at NotificationsScreen (/Users/mac/workspace/nmf-app/app/screens/Notifications/NotificationsScreen.tsx:34:39)".

      67 |   }
      68 |
    > 69 |   if (!hasPermission) {
         |       ^
      70 |     return <PermissionsRequest type="notification" />;
      71 |   }
      72 |

      at NotificationsScreen (app/screens/Notifications/NotificationsScreen.tsx:34:39)".
      at console.error (node_modules/@jest/console/build/BufferedConsole.js:127:10)
      at printWarning (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:72:30)
      at error (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:46:7)
      at warnIfUpdatesNotWrappedWithActDEV (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:16677:9)
      at scheduleUpdateOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14877:5)
      at dispatchSetState (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7510:7)
      at app/screens/Notifications/NotificationsScreen.tsx:69:7
      at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
      at _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)

These tests don't do much, it just matches snapshot of the screens. I am trying to fix these error logs I am new to React Native app, any help is appreciated.

saurabhchatterjee23 commented 8 months ago

I tried to fix these tests but did not succeed. There is a lot of information about this act() warning

I tried wrapping the create() function in act but it didn't fail

One thing in common to both these screens is that they use async method calls in useEffect to check permissions for sending notification or reading barcode

useEffect(() => {
    (async () => {
      const { status } = await BarCodeScanner.requestPermissionsAsync();
      setHasPermission(status === "granted");
    })();
  }, []);
saurabhchatterjee23 commented 8 months ago

These tests are not testing anything significant, the Snapshot it validates is when there is no permission for Camera and Notification, if it helps to get the CI fixed, you might decide to disable these tests for now and enable them again with better coverage

PierreBresson commented 8 months ago

I managed to fix the issue from useEffect with jest.spyOn(React, "useEffect").mockImplementationOnce(()=>{}); But couldn't figured out how to fix the errors following after Yeah, I agree, so I've removed the tests files https://github.com/NMF-earth/nmf-app/commit/9b43d5037173f8c9ec992433f265569f9324a34e

saurabhchatterjee23 commented 8 months ago

Summarizing everything I tried to fix the test to avoid repeated efforts

Move create function call in the test within act()

it("BarCodeScanScreen renders correctly", async () => {
  let tree= null;
  act(() => {
    tree = create(<BarCodeScanScreen />);
  });

  expect(tree.toJSON()).toMatchSnapshot();
});

This didn't fix the issue, however same error was reported on another line in the code

Move to use render and waitFor function call in the test to wait for the useEffect to finish

Added dependency on react-testing-library

it("BarCodeScanScreen renders correctly", async () => {
  const tree = render(<BarCodeScanScreen />);
  waitFor(tree.toJSON()).toMatchSnapshot();
});