Best JavaScript code snippet using playwright-internal
cli.ts
Source:cli.ts  
1#!/usr/bin/env node2// tslint:disable no-console3/*4 * IMPORTANT: the './postgraphilerc' import MUST come first!5 *6 * Reason: enables user to apply modifications to their Node.js environment7 * (e.g. sourcing modules that affect global state, like dotenv) before any of8 * our other require()s occur.9 */10import config from './postgraphilerc';11import * as os from 'os';12import { createServer } from 'http';13import chalk from 'chalk';14import program = require('commander');15import jwt = require('jsonwebtoken');16import { parse as parsePgConnectionString } from 'pg-connection-string';17import postgraphile, { getPostgraphileSchemaBuilder } from './postgraphile';18import { makePgSmartTagsFromFilePlugin } from '../plugins';19import { Pool, PoolConfig } from 'pg';20import cluster = require('cluster');21import { makePluginHook, PostGraphilePlugin } from './pluginHook';22import debugFactory = require('debug');23import { mixed } from '../interfaces';24// @ts-ignore Allow importing JSON25import * as manifest from '../../package.json';26// @ts-ignore Allow importing JSON27import sponsors = require('../../sponsors.json');28import { enhanceHttpServerWithWebSockets } from './http/subscriptions';29import { existsSync } from 'fs';30const tagsFile = process.cwd() + '/postgraphile.tags.json5';31/*32 * Watch mode on the tags file is non-trivial, so only load the plugin if the33 * file exists when PostGraphile starts.34 */35const smartTagsPlugin = existsSync(tagsFile) ? makePgSmartTagsFromFilePlugin() : null;36const isDev = process.env.POSTGRAPHILE_ENV === 'development';37function isString(str: unknown): str is string {38  return typeof str === 'string';39}40const sponsor = sponsors[Math.floor(sponsors.length * Math.random())];41const debugCli = debugFactory('postgraphile:cli');42// TODO: Demo Postgres database43const DEMO_PG_URL = null;44function extractPlugins(45  rawArgv: Array<string>,46): {47  argv: Array<string>;48  plugins: Array<PostGraphilePlugin>;49} {50  let argv;51  let pluginStrings = [];52  if (rawArgv[2] === '--plugins') {53    pluginStrings = rawArgv[3].split(',');54    argv = [...rawArgv.slice(0, 2), ...rawArgv.slice(4)];55  } else {56    pluginStrings = (config && config['options'] && config['options']['plugins']) || [];57    argv = rawArgv;58  }59  const plugins = pluginStrings.map((pluginString: string) => {60    debugCli('Loading plugin %s', pluginString);61    const rawPlugin = require(pluginString); // tslint:disable-lin no-var-requires62    if (rawPlugin['default'] && typeof rawPlugin['default'] === 'object') {63      return rawPlugin['default'];64    } else {65      return rawPlugin;66    }67  });68  return { argv, plugins };69}70const { argv: argvSansPlugins, plugins: extractedPlugins } = extractPlugins(process.argv);71const pluginHook = makePluginHook(extractedPlugins);72program.version(manifest.version).usage('[options...]').description(manifest.description);73// .option('-d, --demo', 'run PostGraphile using the demo database connection')74export type AddFlagFn = (75  optionString: string,76  description: string,77  parse?: (option: string) => mixed,78) => AddFlagFn;79function addFlag(80  optionString: string,81  description: string,82  parse?: (option: string) => mixed,83): AddFlagFn {84  program.option(optionString, description, parse);85  return addFlag;86}87// Standard options88program89  .option(90    '--plugins <string>',91    'a list of PostGraphile server plugins (not Graphile Engine schema plugins) to load; if present, must be the _first_ option',92  )93  .option(94    '-c, --connection <string>',95    "the PostgreSQL database name or connection string. If omitted, inferred from environmental variables (see https://www.postgresql.org/docs/current/static/libpq-envars.html). Examples: 'db', 'postgres:///db', 'postgres://user:password@domain:port/db?ssl=true'",96  )97  .option(98    '-C, --owner-connection <string>',99    'as `--connection`, but for a privileged user (e.g. for setting up watch fixtures, logical decoding, etc); defaults to the value from `--connection`',100  )101  .option(102    '-s, --schema <string>',103    'a Postgres schema to be introspected. Use commas to define multiple schemas',104    (option: string) => option.split(','),105  )106  .option(107    '-S, --subscriptions',108    'Enable GraphQL support for subscriptions (you still need a subscriptions plugin currently)',109  )110  .option(111    '--websockets <string>',112    "Choose which websocket transport libraries to use. Use commas to define multiple. Defaults to 'v0,v1' if `--subscriptions` or `--live` were passed, '[]' otherwise",113    (option: string) => option.split(','),114  )115  .option(116    '--websocket-operations <operations>',117    "Toggle which GraphQL websocket transport operations are supported: 'subscriptions' or 'all'. Defaults to 'subscriptions'",118  )119  .option(120    '-L, --live',121    '[EXPERIMENTAL] Enables live-query support via GraphQL subscriptions (sends updated payload any time nested collections/records change). Implies --subscriptions',122  )123  .option(124    '-w, --watch',125    'automatically updates your GraphQL schema when your database schema changes (NOTE: requires DB superuser to install `postgraphile_watch` schema)',126  )127  .option('-n, --host <string>', 'the hostname to be used. Defaults to `localhost`')128  .option('-p, --port <number>', 'the port to be used. Defaults to 5000', parseFloat)129  .option(130    '-m, --max-pool-size <number>',131    'the maximum number of clients to keep in the Postgres pool. defaults to 10',132    parseFloat,133  )134  .option(135    '-r, --default-role <string>',136    'the default Postgres role to use when a request is made. supercedes the role used to connect to the database',137  )138  .option(139    '--retry-on-init-fail',140    'if an error occurs building the initial schema, this flag will cause PostGraphile to keep trying to build the schema with exponential backoff rather than exiting',141  );142pluginHook('cli:flags:add:standard', addFlag);143// Schema configuration144program145  .option(146    '-j, --dynamic-json',147    '[RECOMMENDED] enable dynamic JSON in GraphQL inputs and outputs. PostGraphile uses stringified JSON by default',148  )149  .option(150    '-N, --no-setof-functions-contain-nulls',151    '[RECOMMENDED] if none of your `RETURNS SETOF compound_type` functions mix NULLs with the results then you may enable this to reduce the nullables in the GraphQL schema',152  )153  .option('-a, --classic-ids', 'use classic global id field name. required to support Relay 1')154  .option(155    '-M, --disable-default-mutations',156    'disable default mutations, mutation will only be possible through Postgres functions',157  )158  .option(159    '--simple-collections <omit|both|only>',160    '"omit" (default) - relay connections only, "only" - simple collections only (no Relay connections), "both" - both',161  )162  .option(163    '--no-ignore-rbac',164    '[RECOMMENDED] set this to exclude fields, queries and mutations that are not available to any possible user (determined from the user in connection string and any role they can become); this will be enabled by default in v5',165  )166  .option(167    '--no-ignore-indexes',168    '[RECOMMENDED] set this to exclude filters, orderBy, and relations that would be expensive to access due to missing indexes',169  )170  .option(171    '--include-extension-resources',172    'by default, tables and functions that come from extensions are excluded; use this flag to include them (not recommended)',173  );174pluginHook('cli:flags:add:schema', addFlag);175// Error enhancements176program177  .option(178    '--show-error-stack [json|string]',179    'show JavaScript error stacks in the GraphQL result errors (recommended in development)',180  )181  .option(182    '--extended-errors <string>',183    "a comma separated list of extended Postgres error fields to display in the GraphQL result. Recommended in development: 'hint,detail,errcode'. Default: none",184    (option: string) => option.split(',').filter(_ => _),185  );186pluginHook('cli:flags:add:errorHandling', addFlag);187// Plugin-related options188program189  .option(190    '--append-plugins <string>',191    'a comma-separated list of plugins to append to the list of Graphile Engine schema plugins',192  )193  .option(194    '--prepend-plugins <string>',195    'a comma-separated list of plugins to prepend to the list of Graphile Engine schema plugins',196  )197  .option(198    '--skip-plugins <string>',199    'a comma-separated list of Graphile Engine schema plugins to skip',200  );201pluginHook('cli:flags:add:plugins', addFlag);202// Things that relate to -X203program204  .option(205    '--read-cache <path>',206    '[experimental] reads cached values from local cache file to improve startup time (you may want to do this in production)',207  )208  .option(209    '--write-cache <path>',210    '[experimental] writes computed values to local cache file so startup can be faster (do this during the build phase)',211  )212  .option(213    '--export-schema-json <path>',214    'enables exporting the detected schema, in JSON format, to the given location. The directories must exist already, if the file exists it will be overwritten.',215  )216  .option(217    '--export-schema-graphql <path>',218    'enables exporting the detected schema, in GraphQL schema format, to the given location. The directories must exist already, if the file exists it will be overwritten.',219  )220  .option(221    '--sort-export',222    'lexicographically (alphabetically) sort exported schema for more stable diffing.',223  )224  .option(225    '-X, --no-server',226    '[experimental] for when you just want to use --write-cache or --export-schema-* and not actually run a server (e.g. CI)',227  );228pluginHook('cli:flags:add:noServer', addFlag);229// Webserver configuration230program231  .option(232    '-q, --graphql <path>',233    'the route to mount the GraphQL server on. defaults to `/graphql`',234  )235  .option(236    '-i, --graphiql <path>',237    'the route to mount the GraphiQL interface on. defaults to `/graphiql`',238  )239  .option(240    '--enhance-graphiql',241    '[DEVELOPMENT] opt in to additional GraphiQL functionality (this may change over time - only intended for use in development; automatically enables with `subscriptions` and `live`)',242  )243  .option(244    '-b, --disable-graphiql',245    'disables the GraphiQL interface. overrides the GraphiQL route option',246  )247  .option(248    '-o, --cors',249    'enable generous CORS settings; disabled by default, if possible use a proxy instead',250  )251  .option(252    '-l, --body-size-limit <string>',253    "set the maximum size of the HTTP request body that can be parsed (default 100kB). The size can be given as a human-readable string, such as '200kB' or '5MB' (case insensitive).",254  )255  .option('--timeout <number>', 'set the timeout value in milliseconds for sockets', parseFloat)256  .option(257    '--cluster-workers <count>',258    '[experimental] spawn <count> workers to increase throughput',259    parseFloat,260  )261  .option(262    '--enable-query-batching',263    '[experimental] enable the server to process multiple GraphQL queries in one request',264  )265  .option('--disable-query-log', 'disable logging queries to console (recommended in production)')266  .option(267    '--allow-explain',268    '[EXPERIMENTAL] allows users to use the Explain button in GraphiQL to view the plan for the SQL that is executed (DO NOT USE IN PRODUCTION)',269  );270pluginHook('cli:flags:add:webserver', addFlag);271// JWT-related options272program273  .option(274    '-e, --jwt-secret <string>',275    'the secret to be used when creating and verifying JWTs. if none is provided auth will be disabled',276  )277  .option(278    '--jwt-verify-algorithms <string>',279    'a comma separated list of the names of the allowed jwt token algorithms',280    (option: string) => option.split(','),281  )282  .option(283    '-A, --jwt-verify-audience <string>',284    "a comma separated list of JWT audiences that will be accepted; defaults to 'postgraphile'. To disable audience verification, set to ''.",285    (option: string) => option.split(',').filter(_ => _),286  )287  .option(288    '--jwt-verify-clock-tolerance <number>',289    'number of seconds to tolerate when checking the nbf and exp claims, to deal with small clock differences among different servers',290    parseFloat,291  )292  .option('--jwt-verify-id <string>', 'the name of the allowed jwt token id')293  .option(294    '--jwt-verify-ignore-expiration',295    'if `true` do not validate the expiration of the token defaults to `false`',296  )297  .option(298    '--jwt-verify-ignore-not-before',299    'if `true` do not validate the notBefore of the token defaults to `false`',300  )301  .option(302    '--jwt-verify-issuer <string>',303    'a comma separated list of the names of the allowed jwt token issuer',304    (option: string) => option.split(','),305  )306  .option('--jwt-verify-subject <string>', 'the name of the allowed jwt token subject')307  .option(308    '--jwt-role <string>',309    'a comma seperated list of strings that create a path in the jwt from which to extract the postgres role. if none is provided it will use the key `role` on the root of the jwt.',310    (option: string) => option.split(','),311  )312  .option(313    '-t, --jwt-token-identifier <identifier>',314    'the Postgres identifier for a composite type that will be used to create JWT tokens',315  );316pluginHook('cli:flags:add:jwt', addFlag);317// Any other options318pluginHook('cli:flags:add', addFlag);319// Deprecated320program321  .option(322    '--token <identifier>',323    '[DEPRECATED] Use --jwt-token-identifier instead. This option will be removed in v5.',324  )325  .option(326    '--secret <string>',327    '[DEPRECATED] Use --jwt-secret instead. This option will be removed in v5.',328  )329  .option(330    '--jwt-audiences <string>',331    '[DEPRECATED] Use --jwt-verify-audience instead. This option will be removed in v5.',332    (option: string) => option.split(','),333  )334  .option(335    '--legacy-functions-only',336    '[DEPRECATED] PostGraphile 4.1.0 introduced support for PostgreSQL functions than declare parameters with IN/OUT/INOUT or declare RETURNS TABLE(...); enable this flag to ignore these types of functions. This option will be removed in v5.',337  );338pluginHook('cli:flags:add:deprecated', addFlag);339// Awkward application workarounds / legacy support340program341  .option(342    '--legacy-relations <omit|deprecated|only>',343    "some one-to-one relations were previously detected as one-to-many - should we export 'only' the old relation shapes, both new and old but mark the old ones as 'deprecated', or 'omit' the old relation shapes entirely",344  )345  .option(346    '--legacy-json-uuid',347    `ONLY use this option if you require the v3 typenames 'Json' and 'Uuid' over 'JSON' and 'UUID'`,348  );349pluginHook('cli:flags:add:workarounds', addFlag);350program.on('--help', () => {351  console.log(`352Get started:353  $ postgraphile354  $ postgraphile -c postgres://localhost/my_db355  $ postgraphile --connection postgres://user:pass@localhost/my_db --schema my_schema --watch --dynamic-json356`);357  process.exit(0);358});359program.parse(argvSansPlugins);360function exitWithErrorMessage(message: string): never {361  console.error(message);362  console.error();363  console.error('For help, run `postgraphile --help`');364  process.exit(1);365}366if (program.args.length) {367  exitWithErrorMessage(368    `ERROR: some of the parameters you passed could not be processed: '${program.args.join(369      "', '",370    )}'`,371  );372}373if (program['plugins']) {374  exitWithErrorMessage(`--plugins must be the first argument to postgraphile if specified`);375}376// Kill server on exit.377process.on('SIGINT', () => {378  process.exit(1);379});380// For `--no-*` options, `program` automatically contains the default,381// overriding our options. We typically want the CLI to "win", but not382// with defaults! So this code extracts those `--no-*` values and383// re-overwrites the values if necessary.384const configOptions = config['options'] || {};385const overridesFromOptions = {};386['ignoreIndexes', 'ignoreRbac', 'setofFunctionsContainNulls'].forEach(option => {387  if (option in configOptions) {388    overridesFromOptions[option] = configOptions[option];389  }390});391// Destruct our configuration file and command line arguments, use defaults, and rename options to392// something appropriate for JavaScript.393const {394  demo: isDemo = false,395  connection: pgConnectionString,396  ownerConnection,397  subscriptions,398  live,399  websockets = subscriptions || live ? ['v0', 'v1'] : [],400  websocketOperations = 'subscriptions',401  watch: watchPg,402  schema: dbSchema,403  host: hostname = 'localhost',404  port = 5000,405  timeout: serverTimeout,406  maxPoolSize,407  defaultRole: pgDefaultRole,408  retryOnInitFail,409  graphql: graphqlRoute = '/graphql',410  graphiql: graphiqlRoute = '/graphiql',411  enhanceGraphiql = false,412  disableGraphiql = false,413  secret: deprecatedJwtSecret,414  jwtSecret,415  jwtPublicKey,416  jwtAudiences,417  jwtVerifyAlgorithms,418  jwtVerifyAudience,419  jwtVerifyClockTolerance,420  jwtVerifyId,421  jwtVerifyIgnoreExpiration,422  jwtVerifyIgnoreNotBefore,423  jwtVerifyIssuer,424  jwtVerifySubject,425  jwtSignOptions = {},426  jwtVerifyOptions: rawJwtVerifyOptions,427  jwtRole = ['role'],428  token: deprecatedJwtPgTypeIdentifier,429  jwtTokenIdentifier: jwtPgTypeIdentifier,430  cors: enableCors = false,431  classicIds = false,432  dynamicJson = false,433  disableDefaultMutations = false,434  ignoreRbac = true,435  includeExtensionResources = false,436  exportSchemaJson: exportJsonSchemaPath,437  exportSchemaGraphql: exportGqlSchemaPath,438  sortExport = false,439  showErrorStack: rawShowErrorStack,440  extendedErrors = [],441  bodySizeLimit,442  appendPlugins: appendPluginNames,443  prependPlugins: prependPluginNames,444  // replaceAllPlugins is NOT exposed via the CLI445  skipPlugins: skipPluginNames,446  readCache,447  writeCache,448  legacyRelations: rawLegacyRelations = 'deprecated',449  server: yesServer,450  clusterWorkers,451  enableQueryBatching,452  setofFunctionsContainNulls = true,453  legacyJsonUuid,454  disableQueryLog,455  allowExplain,456  simpleCollections,457  legacyFunctionsOnly,458  ignoreIndexes,459  // tslint:disable-next-line no-any460} = { ...config['options'], ...program, ...overridesFromOptions } as typeof program;461const showErrorStack = (val => {462  switch (val) {463    case 'string':464    case true:465      return true;466    case null:467    case undefined:468      return undefined;469    case 'json':470      return 'json';471    default: {472      exitWithErrorMessage(473        `Invalid argument for '--show-error-stack' - expected no argument, or 'string' or 'json'`,474      );475    }476  }477})(rawShowErrorStack);478if (allowExplain && !disableGraphiql && !enhanceGraphiql) {479  exitWithErrorMessage('`--allow-explain` requires `--enhance-graphiql` or `--disable-graphiql`');480}481let legacyRelations: 'omit' | 'deprecated' | 'only';482if (!['omit', 'only', 'deprecated'].includes(rawLegacyRelations)) {483  exitWithErrorMessage(484    `Invalid argument to '--legacy-relations' - expected on of 'omit', 'deprecated', 'only'; but received '${rawLegacyRelations}'`,485  );486} else {487  legacyRelations = rawLegacyRelations;488}489// Validate websockets argument490if (491  // must be array492  !Array.isArray(websockets) ||493  // empty array = 'none'494  (websockets.length &&495    // array can only hold the versions496    websockets.some(ver => !['v0', 'v1'].includes(ver)))497) {498  exitWithErrorMessage(499    `Invalid argument to '--websockets' - expected 'v0' and/or 'v1' (separated by comma); but received '${websockets}'`,500  );501}502if (websocketOperations !== 'subscriptions' && websocketOperations !== 'all') {503  exitWithErrorMessage(504    `Invalid argument to '--websocket-operations' - expected 'subscriptions' or 'all' but received '${websocketOperations}'`,505  );506}507const noServer = !yesServer;508// Add custom logic for getting the schemas from our CLI. If we are in demo509// mode, we want to use the `forum_example` schema. Otherwise the `public`510// schema is what we want.511const schemas: Array<string> = dbSchema || (isDemo ? ['forum_example'] : ['public']);512const ownerConnectionString = ownerConnection || pgConnectionString || process.env.DATABASE_URL;513// Work around type mismatches between parsePgConnectionString and PoolConfig514const coerce = (o: ReturnType<typeof parsePgConnectionString>): PoolConfig => {515  const port =516    typeof o.port === 'number'517      ? o.port518      : typeof o.port === 'string'519      ? parseInt(o.port, 10)520      : undefined;521  return {522    ...o,523    application_name: o['application_name'] || undefined,524    ssl:525      o.ssl == null526        ? undefined527        : (o.ssl as any).rejectUnauthorized == null528        ? !!o.ssl529        : (o.ssl as any),530    user: typeof o.user === 'string' ? o.user : undefined,531    database: typeof o.database === 'string' ? o.database : undefined,532    password: typeof o.password === 'string' ? o.password : undefined,533    port: Number.isFinite(port) ? port : undefined,534    host: typeof o.host === 'string' ? o.host : undefined,535  };536};537// Create our Postgres config.538const pgConfig: PoolConfig = {539  // If we have a Postgres connection string, parse it and use that as our540  // config. If we donât have a connection string use some environment541  // variables or final defaults. Other environment variables should be542  // detected and used by `pg`.543  ...(pgConnectionString || process.env.DATABASE_URL || isDemo544    ? coerce(parsePgConnectionString(pgConnectionString || process.env.DATABASE_URL || DEMO_PG_URL))545    : {546        host: process.env.PGHOST || process.env.PGHOSTADDR || 'localhost',547        port: (process.env.PGPORT ? parseInt(process.env.PGPORT, 10) : null) || 5432,548        database: process.env.PGDATABASE,549        user: process.env.PGUSER,550        password: process.env.PGPASSWORD,551      }),552  // Add the max pool size to our config.553  max: maxPoolSize,554};555const loadPlugins = (rawNames: mixed) => {556  if (!rawNames) {557    return undefined;558  }559  const names = Array.isArray(rawNames) ? rawNames : String(rawNames).split(',');560  return names.map(rawName => {561    if (typeof rawName === 'function') {562      return rawName;563    }564    const name = String(rawName);565    const parts = name.split(':');566    if (567      process.platform === 'win32' &&568      parts[0].length === 1 &&569      /^[a-z]$/i.test(parts[0]) &&570      ['\\', '/'].includes(name[2])571    ) {572      // Assume this is a windows path `C:/path/to/module.js` or `C:\path\to\module.js`573      const driveLetter = parts.shift();574      // Add the drive part back onto the path575      parts[0] = `${driveLetter}:${parts[0]}`;576    }577    let root;578    try {579      root = require(String(parts.shift()));580    } catch (e) {581      // tslint:disable-next-line no-console582      console.error(`Failed to load plugin '${name}'`);583      throw e;584    }585    let plugin = root;586    let part: string | void;587    while ((part = parts.shift())) {588      plugin = plugin[part];589      if (plugin == null) {590        throw new Error(`No plugin found matching spec '${name}' - failed at '${part}'`);591      }592    }593    if (typeof plugin === 'function') {594      return plugin;595    } else if (plugin === root && typeof plugin.default === 'function') {596      return plugin.default; // ES6 workaround597    } else {598      throw new Error(599        `No plugin found matching spec '${name}' - expected function, found '${typeof plugin}'`,600      );601    }602  });603};604if (jwtAudiences != null && jwtVerifyAudience != null) {605  exitWithErrorMessage(606    `Provide either '--jwt-audiences' or '-A, --jwt-verify-audience' but not both`,607  );608}609function trimNulls(obj: Record<string, any>): Record<string, any> {610  return Object.keys(obj).reduce((memo, key) => {611    if (obj[key] != null) {612      memo[key] = obj[key];613    }614    return memo;615  }, {});616}617if (618  rawJwtVerifyOptions &&619  (jwtVerifyAlgorithms ||620    jwtVerifyAudience ||621    jwtVerifyClockTolerance ||622    jwtVerifyId ||623    jwtVerifyIgnoreExpiration ||624    jwtVerifyIgnoreNotBefore ||625    jwtVerifyIssuer ||626    jwtVerifySubject)627) {628  exitWithErrorMessage(629    'You may not mix `jwtVerifyOptions` with the legacy `jwtVerify*` settings; please only provide `jwtVerifyOptions`.',630  );631}632const jwtVerifyOptions: jwt.VerifyOptions = rawJwtVerifyOptions633  ? rawJwtVerifyOptions634  : trimNulls({635      algorithms: jwtVerifyAlgorithms,636      audience: jwtVerifyAudience,637      clockTolerance: jwtVerifyClockTolerance,638      jwtId: jwtVerifyId,639      ignoreExpiration: jwtVerifyIgnoreExpiration,640      ignoreNotBefore: jwtVerifyIgnoreNotBefore,641      issuer: jwtVerifyIssuer,642      subject: jwtVerifySubject,643    });644const appendPlugins = loadPlugins(appendPluginNames);645const prependPlugins = loadPlugins(prependPluginNames);646const skipPlugins = loadPlugins(skipPluginNames);647// The options to pass through to the schema builder, or the middleware648const postgraphileOptions = pluginHook(649  'cli:library:options',650  {651    ...config['options'],652    classicIds,653    dynamicJson,654    disableDefaultMutations,655    ignoreRBAC: ignoreRbac,656    includeExtensionResources,657    graphqlRoute,658    graphiqlRoute,659    graphiql: !disableGraphiql,660    enhanceGraphiql: enhanceGraphiql ? true : undefined,661    jwtPgTypeIdentifier: jwtPgTypeIdentifier || deprecatedJwtPgTypeIdentifier,662    jwtSecret: jwtSecret || deprecatedJwtSecret || process.env.JWT_SECRET,663    jwtPublicKey,664    jwtAudiences,665    jwtSignOptions,666    jwtRole,667    jwtVerifyOptions,668    retryOnInitFail,669    pgDefaultRole,670    subscriptions: subscriptions || live,671    websockets,672    websocketOperations,673    live,674    watchPg,675    showErrorStack,676    extendedErrors,677    disableQueryLog,678    allowExplain: allowExplain ? true : undefined,679    enableCors,680    exportJsonSchemaPath,681    exportGqlSchemaPath,682    sortExport,683    bodySizeLimit,684    appendPlugins: smartTagsPlugin ? [smartTagsPlugin, ...(appendPlugins || [])] : appendPlugins,685    prependPlugins,686    skipPlugins,687    readCache,688    writeCache,689    legacyRelations,690    setofFunctionsContainNulls,691    legacyJsonUuid,692    enableQueryBatching,693    pluginHook,694    simpleCollections,695    legacyFunctionsOnly,696    ignoreIndexes,697    ownerConnectionString,698  },699  { config, cliOptions: program },700);701function killAllWorkers(signal = 'SIGTERM'): void {702  for (const id in cluster.workers) {703    const worker = cluster.workers[id];704    if (Object.prototype.hasOwnProperty.call(cluster.workers, id) && worker) {705      worker.kill(signal);706    }707  }708}709if (noServer) {710  // No need for a server, let's just spin up the schema builder711  (async (): Promise<void> => {712    const pgPool = new Pool(pgConfig);713    pgPool.on('error', err => {714      // tslint:disable-next-line no-console715      console.error('PostgreSQL client generated error: ', err.message);716    });717    const { getGraphQLSchema } = getPostgraphileSchemaBuilder(pgPool, schemas, postgraphileOptions);718    await getGraphQLSchema();719    if (!watchPg) {720      await pgPool.end();721    }722  })().then(null, e => {723    console.error('Error occurred!');724    console.error(e);725    process.exit(1);726  });727} else {728  if (clusterWorkers >= 2 && cluster.isMaster) {729    let shuttingDown = false;730    const shutdown = () => {731      if (!shuttingDown) {732        shuttingDown = true;733        process.exitCode = 1;734        const fallbackTimeout = setTimeout(() => {735          const remainingCount = Object.keys(cluster.workers).length;736          if (remainingCount > 0) {737            console.log(738              `  [cluster] ${remainingCount} workers did not die fast enough, sending SIGKILL`,739            );740            killAllWorkers('SIGKILL');741            const ultraFallbackTimeout = setTimeout(() => {742              console.log(743                `  [cluster] really should have exited automatically, but haven't - exiting`,744              );745              process.exit(3);746            }, 5000);747            ultraFallbackTimeout.unref();748          } else {749            console.log(`  [cluster] should have exited automatically, but haven't - exiting`);750            process.exit(2);751          }752        }, 5000);753        fallbackTimeout.unref();754        console.log(`  [cluster] killing other workers with SIGTERM`);755        killAllWorkers('SIGTERM');756      }757    };758    cluster.on('exit', (worker, code, signal) => {759      console.log(760        `  [cluster] worker pid=${worker.process.pid} exited (code=${code}, signal=${signal})`,761      );762      shutdown();763    });764    for (let i = 0; i < clusterWorkers; i++) {765      const worker = cluster.fork({766        POSTGRAPHILE_WORKER_NUMBER: String(i + 1),767      });768      console.log(`  [cluster] started worker ${i + 1} (pid=${worker.process.pid})`);769    }770  } else {771    // Createâs our PostGraphile server772    const rawMiddleware = postgraphile(pgConfig, schemas, postgraphileOptions);773    // You probably don't want this hook; likely you want774    // `postgraphile:middleware` instead. This hook will likely be removed in775    // future without warning.776    const middleware = pluginHook(777      /* DO NOT USE -> */ 'cli:server:middleware' /* <- DO NOT USE */,778      rawMiddleware,779      {780        options: postgraphileOptions,781      },782    );783    const server = createServer(middleware);784    if (serverTimeout) {785      server.timeout = serverTimeout;786    }787    if (websockets.length) {788      enhanceHttpServerWithWebSockets(server, middleware);789    }790    pluginHook('cli:server:created', server, {791      options: postgraphileOptions,792      middleware,793    });794    // Start our server by listening to a specific port and host name. Also log795    // some instructions and other interesting information.796    server.listen(port, hostname, () => {797      const address = server.address();798      const actualPort = typeof address === 'string' ? port : address.port;799      const self = cluster.isMaster800        ? isDev801          ? `server (pid=${process.pid})`802          : 'server'803        : `worker ${process.env.POSTGRAPHILE_WORKER_NUMBER} (pid=${process.pid})`;804      const versionString = `v${manifest.version}`;805      if (cluster.isMaster || process.env.POSTGRAPHILE_WORKER_NUMBER === '1') {806        console.log('');807        console.log(808          `PostGraphile ${versionString} ${self} listening on port ${chalk.underline(809            actualPort.toString(),810          )} ð`,811        );812        console.log('');813        const {814          host: rawPgHost,815          port: rawPgPort,816          database: pgDatabase,817          user: pgUser,818          password: pgPassword,819        } = pgConfig;820        // Not using default because want to handle the empty string also.821        const pgHost = rawPgHost || 'localhost';822        const pgPort = (rawPgPort && parseInt(String(rawPgPort), 10)) || 5432;823        const safeConnectionString = isDemo824          ? 'postgraphile_demo'825          : `postgres://${pgUser ? pgUser : ''}${pgPassword ? ':[SECRET]' : ''}${826              pgUser || pgPassword ? '@' : ''827            }${pgUser || pgPassword || pgHost !== 'localhost' || pgPort !== 5432 ? pgHost : ''}${828              pgPort !== 5432 ? `:${pgConfig.port || 5432}` : ''829            }${pgDatabase ? `/${pgDatabase}` : ''}`;830        const information: Array<string> = pluginHook(831          'cli:greeting',832          [833            `GraphQL API:         ${chalk.underline.bold.blue(834              `http://${hostname}:${actualPort}${graphqlRoute}`,835            )}` +836              (postgraphileOptions.subscriptions837                ? ` (${postgraphileOptions.live ? 'live ' : ''}subscriptions enabled)`838                : ''),839            !disableGraphiql &&840              `GraphiQL GUI/IDE:    ${chalk.underline.bold.blue(841                `http://${hostname}:${actualPort}${graphiqlRoute}`,842              )}` +843                (postgraphileOptions.enhanceGraphiql ||844                postgraphileOptions.live ||845                postgraphileOptions.subscriptions846                  ? ''847                  : ` (${chalk.bold('RECOMMENDATION')}: add '--enhance-graphiql')`),848            `Postgres connection: ${chalk.underline.magenta(safeConnectionString)}${849              postgraphileOptions.watchPg ? ' (watching)' : ''850            }`,851            `Postgres schema(s):  ${schemas.map(schema => chalk.magenta(schema)).join(', ')}`,852            `Documentation:       ${chalk.underline(853              `https://graphile.org/postgraphile/introduction/`,854            )}`,855            `Node.js version:     ${process.version} on ${os.platform()} ${os.arch()}`,856            extractedPlugins.length === 0857              ? `Join ${chalk.bold(858                  sponsor,859                )} in supporting PostGraphile development: ${chalk.underline.bold.blue(860                  `https://graphile.org/sponsor/`,861                )}`862              : null,863          ],864          {865            options: postgraphileOptions,866            middleware,867            port: actualPort,868            chalk,869          },870        ).filter(isString);871        console.log(information.map(msg => `  ⣠${msg}`).join('\n'));872        console.log('');873        console.log(chalk.gray('* * *'));874      } else {875        console.log(876          `PostGraphile ${versionString} ${self} listening on port ${chalk.underline(877            actualPort.toString(),878          )} ð`,879        );880      }881      console.log('');882    });883  }884}...cli.js
Source:cli.js  
...97        }98      };99    });100  }101  const overrides = overridesFromOptions(opts);102  if (opts.headed) overrides.use = {103    headless: false104  };105  const runner = new _runner.Runner(defaultConfig, overrides);106  async function loadConfig(configFile) {107    if (fs.existsSync(configFile)) {108      if (process.stdout.isTTY) console.log(`Using config at ` + configFile);109      const loadedConfig = await runner.loadConfigFile(configFile);110      if ('projects' in loadedConfig && opts.browser) throw new Error(`Cannot use --browser option when configuration file defines projects. Specify browserName in the projects instead.`);111      return true;112    }113    return false;114  }115  async function loadConfigFromDirectory(directory) {116    const configNames = [tsConfig, jsConfig, mjsConfig];117    for (const configName of configNames) {118      if (await loadConfig(path.resolve(directory, configName))) return true;119    }120    return false;121  }122  if (opts.config) {123    const configFile = path.resolve(process.cwd(), opts.config);124    if (!fs.existsSync(configFile)) throw new Error(`${opts.config} does not exist`);125    if (fs.statSync(configFile).isDirectory()) {126      // When passed a directory, look for a config file inside.127      if (!(await loadConfigFromDirectory(configFile))) {128        // If there is no config, assume this as a root testing directory.129        runner.loadEmptyConfig(configFile);130      }131    } else {132      // When passed a file, it must be a config file.133      await loadConfig(configFile);134    }135  } else if (!(await loadConfigFromDirectory(process.cwd()))) {136    // No --config option, let's look for the config file in the current directory.137    // If not, scan the world.138    runner.loadEmptyConfig(process.cwd());139  }140  const filePatternFilters = args.map(arg => {141    const match = /^(.*):(\d+)$/.exec(arg);142    return {143      re: forceRegExp(match ? match[1] : arg),144      line: match ? parseInt(match[2], 10) : null145    };146  });147  const result = await runner.run(!!opts.list, filePatternFilters, opts.project || undefined);148  await (0, _profiler.stopProfiling)(undefined);149  if (result === 'sigint') process.exit(130);150  process.exit(result === 'passed' ? 0 : 1);151}152function forceRegExp(pattern) {153  const match = pattern.match(/^\/(.*)\/([gi]*)$/);154  if (match) return new RegExp(match[1], match[2]);155  return new RegExp(pattern, 'gi');156}157function overridesFromOptions(options) {158  const isDebuggerAttached = !!require('inspector').url();159  const shardPair = options.shard ? options.shard.split('/').map(t => parseInt(t, 10)) : undefined;160  return {161    forbidOnly: options.forbidOnly ? true : undefined,162    globalTimeout: isDebuggerAttached ? 0 : options.globalTimeout ? parseInt(options.globalTimeout, 10) : undefined,163    grep: options.grep ? forceRegExp(options.grep) : undefined,164    grepInvert: options.grepInvert ? forceRegExp(options.grepInvert) : undefined,165    maxFailures: options.x ? 1 : options.maxFailures ? parseInt(options.maxFailures, 10) : undefined,166    outputDir: options.output ? path.resolve(process.cwd(), options.output) : undefined,167    quiet: options.quiet ? options.quiet : undefined,168    repeatEach: options.repeatEach ? parseInt(options.repeatEach, 10) : undefined,169    retries: options.retries ? parseInt(options.retries, 10) : undefined,170    reporter: options.reporter && options.reporter.length ? options.reporter.split(',').map(r => [resolveReporter(r)]) : undefined,171    shard: shardPair ? {...Using AI Code Generation
1const { Playwright } = require('playwright');2const { chromium } = require('playwright-chromium');3const { firefox } = require('playwright-firefox');4const { webkit } = require('playwright-webkit');5const options = {6  viewport: {7  },8  userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36',9  httpCredentials: {10  },11  geolocation: {Using AI Code Generation
1const { overridesFromOptions } = require('playwright/lib/utils/options');2const { chromium } = require('playwright');3(async () => {4    const browser = await chromium.launch({5    });6    const context = await browser.newContext(overridesFromOptions({7        userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36',8        extraHTTPHeaders: {}9    }));10    const page = await context.newPage();11})();Using AI Code Generation
1const { overridesFromOptions } = require('playwright/lib/utils/overrides');2const options = {3  viewport: {4  },5};6const overrides = overridesFromOptions(options);7console.log(overrides);8const { createBrowserContext } = require('playwright/lib/server/browserContext');9const browser = await chromium.launch();10const context = await createBrowserContext(browser, overrides);11console.log(context);12const { createPageInContext } = require('playwright/lib/server/browserContext');13const page = await createPageInContext(context);14console.log(page);15const { createPage } = require('playwright/lib/server/browser');16const page = await createPage(browser, overrides);17console.log(page);18{ ignoreHTTPSErrors: true,19  viewport: { width: 1920, height: 1080 } }20BrowserContext {21  _browser: Browser {22    _connection: Connection {23      _callbacks: Map(0) {},24      _promises: Map(0) {},25      _sessions: Map(0) {},26      _eventListeners: Map(0) {},27      _browser: Browser {28      }29    },30    _browserType: Chromium {31      _options: {}32    },33    _options: { headless: false }34  },35  _options: { ignoreHTTPSErrors: true, viewport: { width: 1920, height: 1080 } },Using AI Code Generation
1const { Playwright } = require('@playwright/test');2const options = {3  viewport: { width: 1280, height: 720 },4  recordVideo: { dir: 'videos' },5  recordTrace: { dir: 'traces' },6  recordHar: { omitContent: true, path: 'trace.har' },7  proxy: {8  },9};10const overrides = Playwright._overridesFromOptions(options);11console.log(overrides);12"scripts": {13  }14{15  viewport: { width: 1280, height: 720 },16  recordVideo: { dir: 'videos' },17  recordTrace: { dir: 'traces' },18  recordHar: { omitContent: true, path: 'trace.har' },19  proxy: {20  },21}22const { Playwright } = require('@playwright/test');23const options = {24  viewport: { width: 1280, height: 720 },25  recordVideo: { dir: 'videos' },26  recordTrace: { dir: 'traces' },27  recordHar: { omitContent: true, path: 'trace.har' },28  proxy: {29  },Using AI Code Generation
1const { chromium } = require('playwright');2const { Internal } = require('playwright/lib/server/browserType');3const browser = await chromium.launch();4const context = await browser.newContext();5const internal = new Internal(browser);6const overrides = internal.overridesFromOptions(context._options);7const { chromium } = require('playwright');8const { Internal } = require('playwright/lib/server/browserType');9const browser = await chromium.launch();10const context = await browser.newContext();11const internal = new Internal(browser);12const overrides = internal.overridesFromOptions(context._options);13const { chromium } = require('playwright');14const { Internal } = require('playwright/lib/server/browserType');15const browser = await chromium.launch();16const context = await browser.newContext();17const internal = new Internal(browser);18const overrides = internal.overridesFromOptions(context._options);Using AI Code Generation
1const { Playwright } = require("playwright");2const playwright = new Playwright({3    {4    },5});6const browser = playwright.chromium.launch({7});8const page = await browser.newPage();9await page.screenshot({ path: "google.png" });10await browser.close();11const { Playwright } = require("playwright");12const playwright = new Playwright({13    {14    },15});16const browser = playwright.chromium.launch({17});18const page = await browser.newPage();19await page.screenshot({ path: "google.png" });20await browser.close();21const { Playwright } = require("playwright");22const playwright = new Playwright({23    {24    },25});26const browser = playwright.chromium.launch({27});28const page = await browser.newPage();29await page.screenshot({ path: "google.png" });30await browser.close();31const { Playwright } = require("playwright");32const playwright = new Playwright({33    {LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!
