text: /* eslint-disable no-magic-numbers */
  /* eslint-disable no-console */
  import {recordUiEdit, stores, storePrefix} from '../src/persistence';
  
  const longString = pow => {
      let s = 's';
      for (let i = 0; i < pow; i++) {
          s += s;
      }
      return s;
  };
  
  const fillStorage = (store, key) => {
      // double the attempted string until we fail
      // then a binary search to find the exact point of failure
      const maxPow = 30;
      let pow = 0;
      for(; pow < maxPow; pow++) {
          try {
              store.setItem(key, longString(pow));
          } catch(e) {
              break;
          }
      }
      pow--;
      let s = longString(pow);
      for(pow--; pow >= 0; pow--) {
          const s2 = s + longString(pow);
          try {
              store.setItem(key, s2);
              s = s2;
          } catch(e) {
              // s remains as is, next time we'll add half as much
          }
      }
      // finally a sanity check that nothing more can be added
      try {
          store.setItem(key + '+', 'a');
      } catch(e) {
          return;
      }
      throw new Error('Something still fits in the store?');
  };
  
  const clearStores = () => {
      window.localStorage.clear();
      window.sessionStorage.clear();
      stores.memory.clear();
      // clear all record of having tested the stores
      delete stores.local;
      delete stores.session;
  };
  
  const layoutA = storeType => ({
      namespace: 'my_components',
      type: 'C',
      props: {
          id: 'a',
          persistence: true,
          persistence_type: storeType
      }
  });
  
  
  describe('storage fallbacks and equivalence', () => {
      const propVal = 42;
      const propStr = String(propVal);
      let originalConsoleErr;
      let consoleCalls;
      let dispatchCalls;
  
      const _dispatch = evt => {
          // verify that dispatch is sending errors to the devtools,
          // and record the message sent
          expect(evt.type).toEqual('ON_ERROR');
          dispatchCalls.push(evt.payload.error.message);
      }
  
      beforeEach(() => {
          window.my_components = {
              C: {
                  defaultProps: {
                      persistence_type: 'local',
                      persisted_props: ['p1', 'p2']
                  }
              }
          };
  
          dispatchCalls = [];
          consoleCalls = [];
          originalConsoleErr = console.error;
          console.error = msg => {
              consoleCalls.push(msg);
          };
  
          clearStores();
      });
  
      afterEach(() => {
          delete window.my_components;
          clearStores();
          console.error = originalConsoleErr;
      });
  
      ['local', 'session'].forEach(storeType => {
          const storeName = storeType + 'Storage';
          const store = window[storeName];
  
          const layout = layoutA(storeType);
  
          test(`empty ${storeName} works`, () => {
              recordUiEdit(layout, {p1: propVal}, _dispatch);
              expect(dispatchCalls).toEqual([]);
              expect(consoleCalls).toEqual([]);
              expect(store.getItem(`${storePrefix}a.p1.true`)).toBe(`[${propStr}]`);
          });
  
          test(`${storeName} full from persistence works with warnings`, () => {
              fillStorage(store, `${storePrefix}x.x`);
  
              recordUiEdit(layout, {p1: propVal}, _dispatch);
              expect(dispatchCalls).toEqual([
                  `${storeName} init first try failed; clearing and retrying`,
                  `${storeName} init set/get succeeded after clearing!`
              ]);
              expect(consoleCalls).toEqual(dispatchCalls);
              expect(store.getItem(`${storePrefix}a.p1.true`)).toBe(`[${propStr}]`);
              // Boolean so we don't see the very long value if test fails
              const x = Boolean(store.getItem(`${storePrefix}x.x`));
              expect(x).toBe(false);
          });
  
          test(`${storeName} full from other stuff falls back on memory`, () => {
              fillStorage(store, 'not_ours');
  
              recordUiEdit(layout, {p1: propVal}, _dispatch);
              expect(dispatchCalls).toEqual([
                  `${storeName} init first try failed; clearing and retrying`,
                  `${storeName} init still failed, falling back to memory`
              ]);
              expect(consoleCalls).toEqual(dispatchCalls);
              expect(stores.memory.getItem('a.p1.true')).toEqual([propVal]);
              const x = Boolean(store.getItem('not_ours'));
              expect(x).toBe(true);
          });
  
          test(`${storeName} that fills up later on just logs an error`, () => {
              // Maybe not ideal long-term behavior, but this is what happens
  
              // initialize and ensure the store is happy
              recordUiEdit(layout, {p1: propVal}, _dispatch);
              expect(dispatchCalls).toEqual([]);
              expect(consoleCalls).toEqual([]);
  
              // now flood it.
              recordUiEdit(layout, {p1: longString(26)}, _dispatch);
              expect(dispatchCalls).toEqual([
                  `a.p1.true failed to save in ${storeName}. Persisted props may be lost.`
              ]);
              expect(consoleCalls).toEqual(dispatchCalls);
          });
      });
  
      ['local', 'session', 'memory'].forEach(storeType => {
          const layout = layoutA(storeType);
          const key = 'key';
  
          test(`${storeType} primitives in/out match`, () => {
              // ensure storage is instantiated
              recordUiEdit(layout, {p1: propVal}, _dispatch);
              const store = stores[storeType];
              [
                  0, 1, 1.1, true, false, null, undefined, '', 'hi', '0', '1'
              ].forEach(val => {
                  store.setItem(key, val);
                  expect(store.getItem(key)).toBe(val);
              });
          });
  
          test(`${storeType} arrays and objects in/out are clones`, () => {
              recordUiEdit(layout, {p1: propVal}, _dispatch);
              const store = stores[storeType];
  
              [[1, 2, 3], {a: 1, b: 2}].forEach(val => {
  
                  store.setItem(key, val);
                  const valOut = store.getItem(key);
                  expect(valOut).not.toBe(val);
                  expect(valOut).toEqual(val);
              });
          });
      });
  });
  