Search code examples
javascriptnode.jscypress

Can pg (Postgres Node Package) Be Used With Cypress?


I'm trying to use the pg module to do cleanup before Cypress tests, but I'm running into a problem.

When I try to use pg in Cypress, like so ...

import { Client } from 'pg';

describe('Some Test Suite', () => {
    beforeEach(async () => {
        const connectionString = 'postgres://someuser@localhost:5432/somedatabase';

        // Next line causes: TypeError: CloudflareSocket is not a constructor
        const client = new Client({ connectionString });
        await client.query('SELECT NOW()');

I get an error:

index-0d246d3b.js:106516 TypeError: CloudflareSocket is not a constructor

It's coming from this code inside Stream.js, inside the pg package:

module.exports.getStream = function getStream(ssl) {
  const net = require('net')
  if (typeof net.Socket === 'function') {
    return new net.Socket()
  } else {
    const { CloudflareSocket } = require('pg-cloudflare')
    return new CloudflareSocket(ssl)
  }
}

From what I've read online, net.Socket should exist (and be a function) as long as its run on the server-side, so I should be using net.Socket(), not CloudflareSocket. By getting this error my code is (evidently?) being run in the browser.

However, I thought Cypress code was run in Node, not the browser, so I'm not sure what I'm getting this error, or how to fix it. Any help would be appreciated.


Solution

  • node-postgres is a node package

    node-postgres is a collection of node.js modules for interfacing with your PostgreSQL database

    You will have to shift your code out of the browser and into a Cypress task, in order to query the database.

    This is a simple example.

    In cypress.config.js

    const { defineConfig } = require("cypress");
    const { Client } = require('pg')
    
    const pgConfig = {
      user: "admin",
      password: "password",
      host: "localhost",
      database: "dbname",
      ssl: false,
      port: 5432
    }
    
    module.exports = defineConfig({
      e2e: {
        setupNodeEvents(on, config) {
          on("task", {
            async queryDb(queryString){
              const client = new Client(pgConfig)
              await client.connect()
              const res = await client.query(queryString)
              await client.end()
              return res.rows;
            }
          })
        },
      },
    })
    

    Mods to the test

    You don't need async to call a task, Cypress awaits a promise returned from the task to resolve before continuing.

    beforeEach(() => {
      cy.task('queryDb', 'SELECT NOW()').then(result => {
        ...