title: How to solve in JEST integrations tests an issue in testing subcriptions WebSocket was closed before the connection was established
body: <p>I have a JEST test file that is not running correctly throwing out this error
  <code>WebSocket was closed before the connection was established</code></p>
  <p>The test is as follows failing immediately without running any other tests</p>
  <pre><code>import { api, gql, ws } from './client';
  import { createCandidate } from './utils';
  
  const query = gql`
    subscription onStatusChanged(
      $studyId: String!
      $types: [CandidateStatusType!]
    ) {
      candidateStatusUpdated(studyId: $studyId, types: $types) {
        id
        studyId
        siteId
        name
        createdAt
        status {
          type
        }
      }
    }
  `;
  
  const mutation = gql`
    mutation updateStatus($id: ID!, $type: CandidateStatusType!) {
      updateCandidateStatus(status: { candidateId: $id, type: $type }) {
        id
      }
    }
  `;
  
  const createHeaders = ({
    actions = ['candidate:get', 'candidate.pii:show'],
    studyId = 'WST2',
    siteId = 'London',
    status = 'INCOMPLETE',
    userId = '6bx9GyxXP4xv2kReGQmX4',
  } = {}) =&gt; ({
    'x-userid': userId,
    'x-permissions': JSON.stringify([
      {
        actions,
        statuses: [status],
        context: {
          studies: ['WST1', studyId],
          sites: ['Madrid', siteId],
        },
      },
    ]),
  });
  
  let client; // The web-socket client
  let candidate1; // study id: WST1
  let candidate2; // study id: WST2
  beforeEach(async () =&gt; {
    candidate1 = await createCandidate({
      studyId: 'WST1',
      siteId: 'Madrid',
      name: 'Test Cand 1',
    });
    candidate2 = await createCandidate({
      studyId: 'WST2',
      siteId: 'London',
      name: 'Test Cand 2',
    });
    client = ws();
    client.onConnected((x) =&gt; x);
  });
  
  afterEach(async () =&gt; {
    await client.onDisconnected((x) =&gt; x);
    await client.close(true);
  });
  
  test('subscribe for study id', (done) =&gt; {
    client = ws(createHeaders());
    client.onConnected(() =&gt; {
      client.request({ query, variables: { studyId: 'WST1' } }).subscribe({
        next({ data: { candidateStatusUpdated } }) {
          expect(candidateStatusUpdated.id).toEqual(candidate1.id);
          expect(candidateStatusUpdated.name).toEqual(candidate1.name);
          expect(candidateStatusUpdated.createdAt).toBeTruthy();
          expect(candidateStatusUpdated.status.type).toEqual(
            'PENDING_CALLCENTER'
          );
          done();
        },
      });
  
      api(mutation, { id: candidate1.id, type: 'PENDING_CALLCENTER' });
    });
  });
  
  test('filter by study id', (done) =&gt; {
    client = ws(createHeaders());
    client.onConnected(async () =&gt; {
      client.request({ query, variables: { studyId: 'WST2' } }).subscribe({
        next() {
          done(`Should not happen because the subscription is for studyId WST2
              and candidate which changed status is from study WST1`);
        },
      });
  
      await api(mutation, { id: candidate1.id, type: 'PENDING_CALLCENTER' });
      setTimeout(() =&gt; done(), 150);
    });
  });
  
  test('subscribe for study id and status types', (done) =&gt; {
    let step = 0; // 0: INITIAL -&gt; 1: PENDING_CALLCENTER -&gt; 2: PENDING_SITE -&gt; 3: REJECTED_SITE -&gt; 4: ANONYMISED
  
    const setStatus = (type) =&gt; {
      step++;
      return api(mutation, { id: candidate2.id, type });
    };
  
    async function callback({ data: { candidateStatusUpdated } }) {
      expect(candidateStatusUpdated.id).toEqual(candidate2.id);
      const statusType = candidateStatusUpdated.status.type;
      switch (step) {
        case 1:
          expect(statusType).toEqual('PENDING_CALLCENTER');
          // This should be ignored due to filter study id
          await api(mutation, { id: candidate1.id, type: 'PENDING_CALLCENTER' });
          // This should be ignored due to filter status types
          await setStatus('PENDING_SITE');
          // Because status type PENDING_SITE is ignored I don't have any callback
          // to trigger the next status update so I have to do it via timer.
          setTimeout(() =&gt; setStatus('REJECTED_SITE'), 100);
          break;
        case 3:
          expect(statusType).toEqual('REJECTED_SITE');
          await setStatus('ANONYMISED');
          // Waiting for nothing to happen and then finish the test.
          setTimeout(() =&gt; done(), 100);
          break;
        default:
          done(`${step}: ${statusType} should be filtered out`);
      }
    }
  
    client = ws(createHeaders());
    client.onConnected(() =&gt; {
      client
        .request({
          query,
          variables: {
            studyId: 'WST2',
            types: ['PENDING_CALLCENTER', 'REJECTED_SITE'],
          },
        })
        .subscribe({ next: callback });
  
      setStatus('PENDING_CALLCENTER');
    });
  });
  
  describe('@authorization', () =&gt; {
    test('should not trigger when not allowed by action', (done) =&gt; {
      client = ws(createHeaders({ actions: ['candidate.pii:show'] }));
      client.onConnected(async () =&gt; {
        client.request({ query, variables: { studyId: 'WST1' } }).subscribe({
          next: () =&gt; done('Should not be triggered'),
        });
  
        await api(mutation, { id: candidate2.id, type: 'PENDING_CALLCENTER' });
        setTimeout(() =&gt; done(), 150);
      });
    });
  
    test('should not trigger when not allowed by studyId', (done) =&gt; {
      client = ws(createHeaders({ studyId: 'FOO' }));
      client.onConnected(async () =&gt; {
        client.request({ query, variables: { studyId: 'WST1' } }).subscribe({
          next: () =&gt; done('Should not be triggered'),
        });
  
        await api(mutation, { id: candidate2.id, type: 'PENDING_CALLCENTER' });
        setTimeout(() =&gt; done(), 150);
      });
    });
  
    test('should not trigger when not allowed by siteId', (done) =&gt; {
      client = ws(createHeaders({ siteId: 'foo' }));
      client.onConnected(async () =&gt; {
        client.request({ query, variables: { studyId: 'WST1' } }).subscribe({
          next: () =&gt; done('Should not be triggered'),
        });
  
        await api(mutation, { id: candidate2.id, type: 'PENDING_CALLCENTER' });
        setTimeout(() =&gt; done(), 150);
      });
    });
  
    test('should mask candidate data when not allowed by status', () =&gt; {
      client = ws(createHeaders({ status: 'PENDING_SITE' }));
      client.onConnected(() =&gt; {
        client.request({ query, variables: { studyId: 'WST1' } }).subscribe({
          next({ data: { candidateStatusUpdated } }) {
            expect(candidateStatusUpdated.id).toEqual(candidate2.id);
            expect(candidateStatusUpdated.studyId).toEqual(candidate2.studyId);
            expect(candidateStatusUpdated.siteId).toEqual(candidate2.siteId);
            expect(candidateStatusUpdated.name).not.toEqual(candidate2.name);
            expect(candidateStatusUpdated.name).toBeFalsy();
            expect(candidateStatusUpdated.status.type).toEqual(
              'PENDING_CALLCENTER'
            );
            done();
          },
        });
  
        api(mutation, { id: candidate2.id, type: 'PENDING_CALLCENTER' });
      });
    });
  });
  </code></pre>
  <p>I have no clue what causing it and how to solve it and I believe the issue is when the <code>beforEach</code> or <code>afterEach</code> happens but don't know what to do.</p>
  <p>The <code>beforeEch</code> uses a utility</p>
  <pre><code>const createCandidate = async (
    {
      studyId,
      siteId,
      name,
      translationId = 101,
      candidate = {},
      statuses = [],
      notes = [],
      comments = [],
      activities = [],
    },
    headers = defaultHeaders
  ) =&gt; {
    const candidateId = (
      await api(
        addCandidate,
        { candidate: { studyId, siteId, name, translationId, ...candidate } },
        headers
      )
    ).addCandidate.id;
  
    // Good old for loop: make sure setStatus transaction is completed before the next setStatus execution otherwise
    for (let i = 0; i &lt; statuses.length; ++i) {
      await api(setStatus, { status: { candidateId, ...statuses[i] } }, headers);
    }
  
    await Promise.all([
      ...notes.map((note) =&gt;
        api(addNote, { note: { candidateId, ...note } }, headers)
      ),
      ...comments.map((comment) =&gt;
        api(addComment, { input: { candidateId, content: comment } }, headers)
      ),
      ...activities.map((activity) =&gt;
        api(addActivity, { activity: { candidateId, ...activity } }, headers)
      ),
    ]);
  
    const {
      listCandidates: { nodes },
    } = await api(getCandidate, { id: candidateId }, headers);
    return nodes[0];
  };
  </code></pre>
  <p>Maybe the issue is from the utility</p>