Comparing version
17
index.js
@@ -7,2 +7,3 @@ #!/usr/bin/env node | ||
// Define the main options | ||
program | ||
@@ -13,2 +14,3 @@ .version(packageJson.version) | ||
.option('-o, --output <outputDir>', 'Output directory for Playwright scripts', process.cwd()) | ||
.option('-f, --format <format>', 'Format of the output scripts (js, ts)', 'js') // Added --format option | ||
.action((options) => { | ||
@@ -18,14 +20,23 @@ if (options.convert) { | ||
const outputDir = path.resolve(options.output); | ||
convertPostmanToPlaywright(postmanCollectionPath, outputDir); | ||
const format = options.format; // Get the format (js or ts) | ||
// Call the conversion function with the additional format parameter | ||
convertPostmanToPlaywright(postmanCollectionPath, outputDir, format); | ||
} | ||
}); | ||
// Define the 'convert' command for more granular control | ||
program | ||
.command('convert <postmanCollectionPath>') | ||
.option('-o, --output <outputDir>', 'Output directory for Playwright scripts', process.cwd()) | ||
.option('-f, --format <format>', 'Format of the output scripts (js, ts)', 'js') // Added --format option here as well | ||
.action((postmanCollectionPath, options) => { | ||
const outputDir = path.resolve(options.output); | ||
convertPostmanToPlaywright(postmanCollectionPath, outputDir); | ||
const format = options.format; // Get the format (js or ts) | ||
// Call the conversion function with the additional format parameter | ||
convertPostmanToPlaywright(postmanCollectionPath, outputDir, format); | ||
}); | ||
// Parse the command line arguments | ||
program.parse(process.argv); | ||
@@ -36,2 +47,2 @@ | ||
program.outputHelp(); | ||
} | ||
} |
{ | ||
"name": "postwright", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "Convert Postman Collections to Playwright scripts", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
 | ||
- [Installation](##installation) | ||
- [Usage](##usage) | ||
- [What does it do presently?](##what-does-it-do-presently) | ||
## Convert your postman collections to playwright scripts. | ||
@@ -13,6 +17,34 @@ --- | ||
- Create a folder and navigate into it then run `postwright -c <location-of-saved-postman-collection>` or `postwright --convert <location-of-saved-postman-collection>` or `postwright convert <location-of-saved-postman-collection>` | ||
- [ ] **Default Javascript** | ||
- You can alternatively run `postwright -c <location-of-saved-postman-collection> -o <preferred-location-to-save-the-converted-script` or `postwright -c <location-of-saved-postman-collection> --output <preferred-location-to-save-the-converted-script` | ||
To convert to a javascript extension, do the following: | ||
- Create a folder and navigate into it then run any of the following: | ||
- `postwright -c <location-of-saved-postman-collection>` | ||
- `postwright --convert <location-of-saved-postman-collection>` | ||
- `postwright convert <location-of-saved-postman-collection>` | ||
- You can alternatively run any of the following from any location in your terminal. | ||
- `postwright -c <location-of-saved-postman-collection> -o <preferred-location-to-save-the-converted-script>` | ||
- `postwright --convert <location-of-saved-postman-collection> --output <preferred-location-to-save-the-converted-script>` | ||
- `postwright -c <location-of-saved-postman-collection> -o <preferred-location-to-save-the-converted-script> -f js` | ||
- `postwright --convert <location-of-saved-postman-collection> --output <preferred-location-to-save-the-converted-script> --format js` | ||
> [!NOTE] | ||
> The default extension is Javascript so it isn't mandatory to add the flag `-f` or `--format` to specify the extension if you want to convert to Javascript. | ||
- [ ] **Convert to Typescript** | ||
To convert to a typescript extension, do the following: | ||
> [!NOTE] | ||
> The ability to convert without specifying an output for Typescript has not been implemented. | ||
- You can run any of the following from any location in your terminal. | ||
- `postwright -c <location-of-saved-postman-collection> -o <preferred-location-to-save-the-converted-script> -f ts` | ||
- `postwright --convert <location-of-saved-postman-collection> --output <preferred-location-to-save-the-converted-script> --format ts` | ||
- `postwright convert <location-of-saved-postman-collection> --output <preferred-location-to-save-the-converted-script> --format ts` | ||
### What does it do presently? | ||
@@ -22,3 +54,3 @@ --- | ||
- [ ] Creates a `variables.js` and `variables.json` files leaving you to decide how you want to parse in saved variables | ||
- [ ] Creates a `variables.js` or a `variable.ts` and `variables.json` files depending on which format that's specified when converting. This lets you to decide how you want to parse in saved variables | ||
@@ -29,1 +61,2 @@ - [ ] Offers basic post-response assertions which are status code and response time. It extracts the title of other tests so that you can write them manually. | ||
> This is a first release, the plugin shall be improved upon to better handle post-response tests and pre-request scripts. | ||
> If any variable is hyphenated, the `variable.js` or `variable.ts` file will be created with the hyphenated variable name and that will cause an error. Change variable names to camel case or snake case to avoid this. |
@@ -1,16 +0,30 @@ | ||
const fs = require('fs').promises; | ||
const path = require('path'); | ||
const { processCollection } = require('./scriptGenerator.js'); | ||
const fs = require("fs").promises; | ||
const path = require("path"); | ||
const { processCollection } = require("./scriptGenerator.js"); | ||
async function convertPostmanToPlaywright(postmanCollectionPath, outputDir = process.cwd()) { | ||
async function convertPostmanToPlaywright( | ||
postmanCollectionPath, | ||
outputDir = process.cwd(), | ||
format = "js"// Default to 'js' (JavaScript) | ||
) { | ||
try { | ||
const postmanCollection = JSON.parse(await fs.readFile(postmanCollectionPath, 'utf-8')); | ||
const postmanCollection = JSON.parse( | ||
await fs.readFile(postmanCollectionPath, "utf-8") | ||
); | ||
await fs.mkdir(outputDir, { recursive: true }); | ||
await processCollection(postmanCollection, outputDir); | ||
let itemCounter = 0; | ||
await processCollection(postmanCollection, outputDir, format); | ||
console.log('Conversion complete. Playwright scripts have been generated.'); | ||
// Create tsconfig.json if TypeScript is chosen | ||
if (format === "ts") { | ||
await createTsConfig(outputDir); | ||
} | ||
console.log( | ||
`Conversion complete. Playwright scripts have been generated in ${outputDir}` | ||
); | ||
} catch (error) { | ||
console.error('Error converting Postman collection:', error.message); | ||
console.error("Error converting Postman collection:", error.message); | ||
process.exit(1); | ||
@@ -20,2 +34,25 @@ } | ||
module.exports = { convertPostmanToPlaywright }; | ||
async function createTsConfig(outputDir) { | ||
const tsConfigContent = { | ||
compilerOptions: { | ||
target: "ES6", | ||
module: "CommonJS", | ||
strict: true, | ||
esModuleInterop: true, | ||
skipLibCheck: true, | ||
forceConsistentCasingInFileNames: true, | ||
}, | ||
include: ["**/*.ts"], | ||
}; | ||
const tsConfigPath = path.join(outputDir, "tsconfig.json"); | ||
await fs.writeFile( | ||
tsConfigPath, | ||
JSON.stringify(tsConfigContent, null, 2), | ||
"utf8" | ||
); | ||
console.log("tsconfig.json created."); | ||
} | ||
module.exports = { convertPostmanToPlaywright }; |
@@ -8,2 +8,5 @@ const fs = require("fs").promises; | ||
let convertedScripts = new Map(); | ||
let variablesJsPath; | ||
let fileName; | ||
let variableEntries; | ||
@@ -26,3 +29,3 @@ async function loadVariables(outputDir) { | ||
async function saveVariables(outputDir) { | ||
async function saveVariables(outputDir, format) { | ||
if (!outputDir) { | ||
@@ -32,2 +35,4 @@ console.error("Output directory is undefined"); | ||
} | ||
// Save as JSON | ||
const variablesFilePath = path.join(outputDir, "variables.json"); | ||
@@ -57,6 +62,14 @@ await fs.writeFile( | ||
) { | ||
const match = line.match(/set$$"(.+?)",\s*(.+?)$$/); | ||
const match = line.match(/set\("(.+?)",\s*(.+?)\)/); | ||
if (match) { | ||
const [, key, value] = match; | ||
convertedScript += ` variables['${key}'] = ${value};\n`; | ||
convertedScript += ` variables['${key}'] : ${value};\n`; | ||
variableEntries = Object.entries(variables) | ||
.map(([key, value]) => { | ||
const valueType = typeof value; | ||
const formattedValue = | ||
valueType === "string" ? `'${value}'` : JSON.stringify(value); | ||
return ` ${key}: ${formattedValue}`; | ||
}) | ||
.join(",\n"); | ||
} | ||
@@ -114,4 +127,3 @@ } else { | ||
jsonAssignmentFound = true; | ||
} | ||
} | ||
} | ||
@@ -124,3 +136,3 @@ }); | ||
function generatePlaywrightTest(item, folderPath, outputDir) { | ||
function generatePlaywrightTest(item, folderPath, outputDir, useTypeScript) { | ||
const { name, request, event } = item; | ||
@@ -131,2 +143,3 @@ const { method, url, header, body } = request; | ||
let postResponseScript = ""; | ||
let variablesImport; | ||
@@ -165,31 +178,36 @@ if (event) { | ||
// Check if url and url.raw exist before using it | ||
const requestUrl = url && url.raw ? replaceVariables(url.raw) : "undefined_url"; | ||
const requestUrl = | ||
url && url.raw ? replaceVariables(url.raw) : "undefined_url"; | ||
const relativePath = path.relative(folderPath, outputDir).replace(/\\/g, "/"); | ||
const variablesImport = relativePath | ||
? `import { variables } from '${relativePath}/variables.js';` | ||
: `import { variables } from './variables.js';`; | ||
variablesImport = `import { variables } from './variables.${ | ||
useTypeScript === "ts" ? "ts" : "js" | ||
}';`; | ||
return ` | ||
import { test, expect } from '@playwright/test'; | ||
import { test, expect ${ | ||
useTypeScript === "ts" ? ", APIRequestContext" : "" | ||
} } from '@playwright/test'; | ||
${variablesImport} | ||
${ | ||
useTypeScript === "ts" | ||
? "type TestContext = { request: APIRequestContext };" | ||
: "" | ||
} | ||
test('${name}', async ({ request }) => { | ||
test('${name}', async ({ request }${ | ||
useTypeScript === "ts" ? ": TestContext" : "" | ||
}) => { | ||
${preRequestScript} | ||
const startTime = Date.now(); | ||
const response = await request.${method.toLowerCase()}('${requestUrl}'${ | ||
Object.keys(requestOptions).length > 0 | ||
? `, ${JSON.stringify(requestOptions, null, 2)}` | ||
: "" | ||
}); | ||
const response = await request.${method.toLowerCase()}('${ | ||
url.raw || "undefined_url" | ||
}'); | ||
const responseTime = Date.now() - startTime; | ||
${postResponseScript} | ||
}); | ||
`; | ||
`; | ||
} | ||
async function processItem(item, parentPath = "", outputDir) { | ||
async function processItem(item, parentPath = "", outputDir, useTypeScript) { | ||
if (!outputDir) { | ||
@@ -203,3 +221,3 @@ console.error("Output directory is undefined"); | ||
// This is a folder | ||
const folderPath = path.join( | ||
folderPath = path.join( | ||
parentPath, | ||
@@ -211,10 +229,22 @@ `${itemNumber}_${item.name.replace(/[^a-z0-9]/gi, "_").toLowerCase()}` | ||
for (const subItem of item.item) { | ||
await processItem(subItem, folderPath, outputDir); | ||
await processItem(subItem, folderPath, outputDir, useTypeScript); | ||
} | ||
} else if (item.request) { | ||
// This is a request | ||
const testScript = generatePlaywrightTest(item, parentPath, outputDir); | ||
const fileName = `${itemNumber}_${item.name | ||
.replace(/[^a-z0-9]/gi, "_") | ||
.toLowerCase()}.spec.js`; | ||
const testScript = generatePlaywrightTest( | ||
item, | ||
folderPath, | ||
outputDir, | ||
useTypeScript | ||
); | ||
if (useTypeScript === "ts") { | ||
fileName = `${itemNumber}_${item.name | ||
.replace(/[^a-z0-9]/gi, "_") | ||
.toLowerCase()}.spec.ts`; | ||
} else { | ||
fileName = `${itemNumber}_${item.name | ||
.replace(/[^a-z0-9]/gi, "_") | ||
.toLowerCase()}.spec.js`; | ||
} | ||
const filePath = path.join(parentPath, fileName); | ||
@@ -225,3 +255,3 @@ await fs.writeFile(filePath, testScript); | ||
async function processCollection(collection, outputDir) { | ||
async function processCollection(collection, outputDir, useTypeScript) { | ||
if (!outputDir) { | ||
@@ -241,5 +271,5 @@ throw new Error("Output directory is undefined"); | ||
itemCounter = 0; | ||
convertedScripts.clear(); // Clear the converted scripts before processing a new collection | ||
convertedScripts.clear(); | ||
for (const item of collection.item) { | ||
await processItem(item, outputDir, outputDir); | ||
await processItem(item, outputDir, outputDir, useTypeScript); | ||
} | ||
@@ -249,9 +279,9 @@ | ||
// Create a variables.js file to export the variables | ||
const variablesJsContent = `export const variables = ${JSON.stringify( | ||
variables, | ||
null, | ||
2 | ||
)};`; | ||
const variablesJsPath = path.join(outputDir, "variables.js"); | ||
const variablesJsContent = `export const Variables = {\n${variableEntries}\n};\n`; | ||
if (useTypeScript === "ts") { | ||
variablesJsPath = path.join(outputDir, "variables.ts"); | ||
} else { | ||
variablesJsPath = path.join(outputDir, "variables.js"); | ||
} | ||
await fs.writeFile(variablesJsPath, variablesJsContent); | ||
@@ -258,0 +288,0 @@ } |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
121842
12.88%12
50%331
28.79%59
118.52%