commit
06512f3a2a
@ -0,0 +1,242 @@ |
|||||||
|
import { Octokit } from 'octokit' |
||||||
|
import * as fs from 'fs' |
||||||
|
import * as path from 'path' |
||||||
|
import YAML from 'yaml' |
||||||
|
import crypto from 'crypto' |
||||||
|
|
||||||
|
const owner = 'remix-project-org' |
||||||
|
let repo = 'remix-desktop' |
||||||
|
const headers = { |
||||||
|
'X-GitHub-Api-Version': '2022-11-28', |
||||||
|
} |
||||||
|
|
||||||
|
const version = getVersionFromPackageJson() |
||||||
|
let channel = 'latest' |
||||||
|
|
||||||
|
if (version.includes('beta')) { |
||||||
|
channel = 'beta' |
||||||
|
} |
||||||
|
if (version.includes('alpha')) { |
||||||
|
channel = 'alpha' |
||||||
|
} |
||||||
|
if (version.includes('insiders')) { |
||||||
|
channel = 'insiders' |
||||||
|
} |
||||||
|
|
||||||
|
if (channel !== 'latest') repo = `remix-desktop-${channel}` |
||||||
|
|
||||||
|
const octokit = new Octokit({ |
||||||
|
auth: process.env.GH_TOKEN_DESKTOP_PUBLISH, |
||||||
|
}) |
||||||
|
|
||||||
|
async function getAllReleases() { |
||||||
|
const releases = await octokit.request('GET /repos/{owner}/{repo}/releases', { |
||||||
|
owner: owner, |
||||||
|
repo: repo, |
||||||
|
headers: headers, |
||||||
|
}) |
||||||
|
return releases.data |
||||||
|
} |
||||||
|
|
||||||
|
async function uploadReleaseAsset(release, name, file) { |
||||||
|
const upload_url = release.upload_url |
||||||
|
console.log(`Uploading ${name} to ${upload_url}`) |
||||||
|
if (fs.existsSync(file)) { |
||||||
|
octokit.request({ |
||||||
|
method: "POST", |
||||||
|
url: upload_url, |
||||||
|
headers: { |
||||||
|
"content-type": "text/plain", |
||||||
|
}, |
||||||
|
data: fs.readFileSync(file), |
||||||
|
name, |
||||||
|
label: name |
||||||
|
}); |
||||||
|
} else { |
||||||
|
console.log(`File ${file} does not exist. Skipping...`) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function getVersionFromPackageJson() { |
||||||
|
// ignore ts error
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const packageJson = require(__dirname + '/../../../apps/remixdesktop/package.json') |
||||||
|
return packageJson.version |
||||||
|
} |
||||||
|
|
||||||
|
async function readReleaseFilesFromLocalDirectory() { |
||||||
|
const directoryPath = path.join(__dirname, '../../../release') |
||||||
|
const files = fs.readdirSync(directoryPath) |
||||||
|
return files |
||||||
|
} |
||||||
|
|
||||||
|
async function removeAsset(asset) { |
||||||
|
await octokit.request('DELETE /repos/{owner}/{repo}/releases/assets/{asset_id}', { |
||||||
|
owner: owner, |
||||||
|
repo: repo, |
||||||
|
asset_id: asset.id, |
||||||
|
headers: headers, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
async function hashFile(file): Promise<string> { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const hash = crypto.createHash('sha512').setEncoding('base64'); |
||||||
|
// hash.on('error', reject).setEncoding(encoding);
|
||||||
|
fs.createReadStream( |
||||||
|
file, |
||||||
|
Object.assign({}, {}, { |
||||||
|
highWaterMark: 1024 * 1024, |
||||||
|
/* better to use more memory but hash faster */ |
||||||
|
}) |
||||||
|
) |
||||||
|
.on('error', reject) |
||||||
|
.on('end', () => { |
||||||
|
hash.end(); |
||||||
|
console.log('hash done'); |
||||||
|
console.log(hash.read()); |
||||||
|
resolve(hash.digest('base64')); |
||||||
|
}) |
||||||
|
.pipe( |
||||||
|
hash, |
||||||
|
{ |
||||||
|
end: false, |
||||||
|
} |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
async function main() { |
||||||
|
|
||||||
|
const allReleases = await getAllReleases() |
||||||
|
|
||||||
|
console.log(`preparing release version: ${version}`) |
||||||
|
let release |
||||||
|
allReleases.find((r) => { |
||||||
|
if (r.tag_name === `v${version}`) { |
||||||
|
release = r |
||||||
|
} |
||||||
|
}) |
||||||
|
if (!release) { |
||||||
|
console.log('No release found.') |
||||||
|
// create release
|
||||||
|
console.log(`Creating release ${version}`) |
||||||
|
const r = await octokit.request('POST /repos/{owner}/{repo}/releases', { |
||||||
|
owner: owner, |
||||||
|
repo: repo, |
||||||
|
tag_name: `v${version}`, |
||||||
|
name: `${version}`, |
||||||
|
draft: true, |
||||||
|
prerelease: true, |
||||||
|
headers: headers, |
||||||
|
}) |
||||||
|
release = r.data |
||||||
|
} |
||||||
|
|
||||||
|
let ymlFiles = await readReleaseFilesFromLocalDirectory() |
||||||
|
ymlFiles = ymlFiles.filter((file) => file.endsWith('.yml') && file.startsWith('latest')) |
||||||
|
|
||||||
|
console.log(`Found ${ymlFiles.length} yml files to upload`) |
||||||
|
|
||||||
|
// read and parse yml latest files
|
||||||
|
// the yml files contain the sha512 hash and file size of the executable
|
||||||
|
// we need to recalculate the hash and file size of the executable
|
||||||
|
// and update the yml files
|
||||||
|
// this is because the executable is resigned after the yml files are created
|
||||||
|
for (const file of ymlFiles) { |
||||||
|
const content = fs.readFileSync(path.join(__dirname, '../../../release', file), 'utf8') |
||||||
|
const parsed = YAML.parse(content) |
||||||
|
const hashes: { |
||||||
|
url: string, |
||||||
|
sha512: string, |
||||||
|
size: number |
||||||
|
}[] = [] |
||||||
|
if (parsed.files) { |
||||||
|
console.log(`Found`, parsed.files) |
||||||
|
for (const f of parsed.files) { |
||||||
|
const executable = f.url |
||||||
|
const exists = fs.existsSync(path.join(__dirname, '../../../release', executable)) |
||||||
|
if (!exists) { |
||||||
|
console.log(`File ${executable} does not exist on local fs. Skipping...`) |
||||||
|
continue |
||||||
|
} else { |
||||||
|
console.log(`File ${executable} exists on local fs. Recalculating hash...`) |
||||||
|
// calculate sha512 hash of executable
|
||||||
|
const hash: string = await hashFile(path.join(__dirname, '../../../release', executable)) |
||||||
|
console.log(hash) |
||||||
|
// calculate file size of executable
|
||||||
|
const stats = fs.statSync(path.join(__dirname, '../../../release', executable)) |
||||||
|
const fileSizeInBytes = stats.size |
||||||
|
console.log(fileSizeInBytes) |
||||||
|
hashes.push({ |
||||||
|
url: executable, |
||||||
|
sha512: hash, |
||||||
|
size: fileSizeInBytes |
||||||
|
}) |
||||||
|
if (parsed.path === executable) { |
||||||
|
parsed.sha512 = hash |
||||||
|
parsed.size = fileSizeInBytes |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
console.log(hashes) |
||||||
|
parsed.files = hashes |
||||||
|
const newYml = YAML.stringify(parsed) |
||||||
|
fs.writeFileSync(path.join(__dirname, '../../../release', file), newYml) |
||||||
|
} |
||||||
|
|
||||||
|
let files = await readReleaseFilesFromLocalDirectory() |
||||||
|
|
||||||
|
try { |
||||||
|
if (fs.existsSync(path.join(__dirname, '../../../release', `latest-mac-arm64.yml`)) && fs.existsSync(path.join(__dirname, '../../../release', `latest-mac-x64.yml`))) { |
||||||
|
// combine the two files
|
||||||
|
const macArm64 = fs.readFileSync(path.join(__dirname, '../../../release', `latest-mac-arm64.yml`), 'utf8') |
||||||
|
const mac = fs.readFileSync(path.join(__dirname, '../../../release', `latest-mac-x64.yml`), 'utf8') |
||||||
|
const parsedMacArm64 = YAML.parse(macArm64) |
||||||
|
const parsedMac = YAML.parse(mac) |
||||||
|
console.log(parsedMacArm64) |
||||||
|
console.log(parsedMac) |
||||||
|
const combined = { |
||||||
|
...parsedMac, |
||||||
|
files: [ |
||||||
|
...parsedMac.files, |
||||||
|
...parsedMacArm64.files |
||||||
|
] |
||||||
|
} |
||||||
|
console.log(combined) |
||||||
|
const newYml = YAML.stringify(combined) |
||||||
|
fs.writeFileSync(path.join(__dirname, '../../../release', `latest-mac.yml`), newYml) |
||||||
|
// remove the arm64 file
|
||||||
|
fs.unlinkSync(path.join(__dirname, '../../../release', `latest-mac-arm64.yml`)) |
||||||
|
fs.unlinkSync(path.join(__dirname, '../../../release', `latest-mac-x64.yml`)) |
||||||
|
} |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
|
||||||
|
files = await readReleaseFilesFromLocalDirectory() |
||||||
|
files = files. |
||||||
|
filter((file) => file.endsWith('.zip') || file.endsWith('.dmg') || file.endsWith('.exe') || file.endsWith('.AppImage') || file.endsWith('.snap') || file.endsWith('.deb') || file.startsWith(`latest`)) |
||||||
|
.filter((file) => !file.startsWith('._')) |
||||||
|
console.log(`Found ${files.length} files to upload`) |
||||||
|
console.log(files) |
||||||
|
if (!release.draft) { |
||||||
|
console.log(`Release ${version} is not a draft. Aborting...`) |
||||||
|
return |
||||||
|
} |
||||||
|
// upload files
|
||||||
|
for (const file of files) { |
||||||
|
// check if it is already uploaded
|
||||||
|
const asset = release.assets.find((a) => a.label === file) |
||||||
|
if (asset) { |
||||||
|
console.log(`Asset ${file} already uploaded... replacing it`) |
||||||
|
// remove it first
|
||||||
|
await removeAsset(asset) |
||||||
|
} |
||||||
|
await uploadReleaseAsset(release, file, path.join(__dirname, '../../../release', file)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
main() |
||||||
|
|
@ -0,0 +1,54 @@ |
|||||||
|
import { ElectronPlugin } from '@remixproject/engine-electron' |
||||||
|
|
||||||
|
const profile = { |
||||||
|
displayName: 'appUpdater', |
||||||
|
name: 'appUpdater', |
||||||
|
description: 'appUpdater', |
||||||
|
} |
||||||
|
|
||||||
|
export class appUpdaterPlugin extends ElectronPlugin { |
||||||
|
constructor() { |
||||||
|
super(profile) |
||||||
|
} |
||||||
|
|
||||||
|
onActivation(): void { |
||||||
|
this.on('appUpdater', 'askForUpdate', () => { |
||||||
|
console.log('askForUpdate') |
||||||
|
const upgradeModal = { |
||||||
|
id: 'confirmUpdate', |
||||||
|
title: 'An update is available', |
||||||
|
message: `A new version of Remix Desktop is available. Do you want to update?`, |
||||||
|
modalType: 'modal', |
||||||
|
okLabel: 'Yes', |
||||||
|
cancelLabel: 'No', |
||||||
|
okFn: () => { |
||||||
|
this.call('appUpdater', 'download') |
||||||
|
}, |
||||||
|
cancelFn: () => { |
||||||
|
|
||||||
|
}, |
||||||
|
hideFn: () => null |
||||||
|
} |
||||||
|
this.call('notification', 'modal', upgradeModal) |
||||||
|
}) |
||||||
|
this.on('appUpdater', 'downloadReady', () => { |
||||||
|
console.log('downloadReady') |
||||||
|
const upgradeModal = { |
||||||
|
id: 'confirmInstall', |
||||||
|
title: 'An update is ready to install', |
||||||
|
message: `A new version of Remix Desktop is ready to install. Do you want to install it now? This will close Remix Desktop.`, |
||||||
|
modalType: 'modal', |
||||||
|
okLabel: 'Yes', |
||||||
|
cancelLabel: 'No', |
||||||
|
okFn: () => { |
||||||
|
this.call('appUpdater', 'install') |
||||||
|
}, |
||||||
|
cancelFn: () => { |
||||||
|
|
||||||
|
}, |
||||||
|
hideFn: () => null |
||||||
|
} |
||||||
|
this.call('notification', 'modal', upgradeModal) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
import { ElectronPlugin } from '@remixproject/engine-electron'; |
||||||
|
|
||||||
|
export class FoundryHandleDesktop extends ElectronPlugin { |
||||||
|
constructor() { |
||||||
|
super({ |
||||||
|
displayName: 'foundry', |
||||||
|
name: 'foundry', |
||||||
|
description: 'electron foundry', |
||||||
|
methods: ['sync', 'compile'] |
||||||
|
}) |
||||||
|
this.methods = ['sync', 'compile'] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
import { ElectronPlugin } from '@remixproject/engine-electron'; |
||||||
|
|
||||||
|
export class HardhatHandleDesktop extends ElectronPlugin { |
||||||
|
constructor() { |
||||||
|
super({ |
||||||
|
displayName: 'hardhat', |
||||||
|
name: 'hardhat', |
||||||
|
description: 'electron hardhat', |
||||||
|
methods: ['sync', 'compile'] |
||||||
|
}) |
||||||
|
this.methods = ['sync', 'compile'] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
import { ElectronPlugin } from '@remixproject/engine-electron'; |
||||||
|
|
||||||
|
export class SlitherHandleDesktop extends ElectronPlugin { |
||||||
|
constructor() { |
||||||
|
super({ |
||||||
|
displayName: 'slither', |
||||||
|
name: 'slither', |
||||||
|
description: 'electron slither', |
||||||
|
methods: ['analyse'] |
||||||
|
}) |
||||||
|
this.methods = ['analyse'] |
||||||
|
} |
||||||
|
} |
@ -1,4 +1,6 @@ |
|||||||
{ |
{ |
||||||
"electron.openFolder": "Open Folder", |
"electron.openFolder": "Open Folder", |
||||||
"electron.recentFolders": "Recent Folders" |
"electron.recentFolders": "Recent Folders", |
||||||
|
"electron.gitClone": "Clone a Git Repository", |
||||||
|
"electron.openFolderMessage": "In order to use Git features, you can open a folder or clone a repository." |
||||||
} |
} |
@ -0,0 +1,3 @@ |
|||||||
|
{ |
||||||
|
"gitui.openFolderMessage": "In order to use Git features, you can open a folder or clone a repository." |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
const fs = require('fs-extra'); |
||||||
|
const path = require('path'); |
||||||
|
|
||||||
|
exports.default = async function (context) { |
||||||
|
console.log('Running after-pack hook', context); |
||||||
|
const resourcesPath = context.appOutDir; |
||||||
|
console.log('resourcesPath', resourcesPath); |
||||||
|
console.log('context outdir', context.appOutDir); |
||||||
|
// Copy the node-pty module to the app folder
|
||||||
|
await fs.copy( |
||||||
|
path.join('./node_modules', 'node-pty'), |
||||||
|
path.join(resourcesPath, 'node_modules', 'node-pty') |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,30 @@ |
|||||||
|
const fs = require('fs'); |
||||||
|
|
||||||
|
exports.default = async function afterbuild(context) { |
||||||
|
// do not run when not on macOS or when not on CIRCLECI
|
||||||
|
if (process.platform !== 'darwin' || !process.env.CIRCLE_BRANCH) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
console.log('AFTER BUILD', context); |
||||||
|
|
||||||
|
const artifactPaths = context.artifactPaths; |
||||||
|
const newDmgs = artifactPaths.filter((dmg) => dmg.endsWith('.dmg')).map((dmg) => dmg); // Removed unnecessary quotes for consistency
|
||||||
|
|
||||||
|
let existingDmgs = []; |
||||||
|
try { |
||||||
|
// Attempt to read the existing dmgs.json file
|
||||||
|
const data = fs.readFileSync('dmgs.json', 'utf8'); |
||||||
|
const parsedData = JSON.parse(data); |
||||||
|
existingDmgs = parsedData.dmgs || []; // Ensure existingDmgs is an array
|
||||||
|
} catch (error) { |
||||||
|
// If there's an error reading the file (e.g., file does not exist), proceed with an empty array
|
||||||
|
console.log('No existing dmgs.json or error reading file, creating new one.'); |
||||||
|
} |
||||||
|
|
||||||
|
// Combine existing and new dmgs, avoiding duplicates
|
||||||
|
const combinedDmgs = [...new Set([...existingDmgs, ...newDmgs])]; |
||||||
|
|
||||||
|
// Write/overwrite the dmgs.json with the combined list of dmgs
|
||||||
|
fs.writeFileSync('dmgs.json', JSON.stringify({ dmgs: combinedDmgs }, null, 2)); |
||||||
|
}; |
@ -0,0 +1,104 @@ |
|||||||
|
const { notarize } = require('@electron/notarize') |
||||||
|
const fs = require('fs') |
||||||
|
const { exec } = require('child_process') // Import the exec function
|
||||||
|
|
||||||
|
// read the environment variables from process
|
||||||
|
|
||||||
|
console.log(process.env.DO_NOT_NOTARIZE) |
||||||
|
|
||||||
|
if (process.env.DO_NOT_NOTARIZE) { |
||||||
|
console.log('NOTARIZING DISABLED') |
||||||
|
exports.default = async function notarizing(context) { |
||||||
|
return [] |
||||||
|
} |
||||||
|
} else { |
||||||
|
|
||||||
|
exports.default = async function notarizing(context) { |
||||||
|
const { electronPlatformName, appOutDir } = context // Provided by electron-builder
|
||||||
|
|
||||||
|
console.log('NOTARIZING') |
||||||
|
|
||||||
|
if (electronPlatformName !== 'darwin' || !process.env.CIRCLE_BRANCH) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
const appName = context.packager.appInfo.productFilename |
||||||
|
const appPath = `${appOutDir}/${appName}.app` |
||||||
|
|
||||||
|
// Function to promisify the exec command
|
||||||
|
function execShellCommand(cmd) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
exec(cmd, (error, stdout, stderr) => { |
||||||
|
if (error) { |
||||||
|
reject(new Error(`Error: ${error.message}`)); |
||||||
|
return; |
||||||
|
} |
||||||
|
if (stderr) { |
||||||
|
reject(new Error(`Stderr: ${stderr}`)); |
||||||
|
return; |
||||||
|
} |
||||||
|
console.log(`stdout: ${stdout}`); |
||||||
|
resolve(stdout); |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
// Function to check if the app is stapled
|
||||||
|
// Async function to check the stapling status
|
||||||
|
async function checkStapleStatus() { |
||||||
|
try { |
||||||
|
console.log(`xcrun stapler validate "${appPath}"`) |
||||||
|
await execShellCommand(`xcrun stapler validate "${appPath}"`); |
||||||
|
console.log('App is already stapled. No action needed.'); |
||||||
|
return true |
||||||
|
} catch (error) { |
||||||
|
console.log(`App is not stapled: ${error.message}`); |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function runNotarize() { |
||||||
|
|
||||||
|
console.log('NOTARIZING + ', `xcrun stapler staple "${appPath}"`) |
||||||
|
console.log({ |
||||||
|
appBundleId: 'org.ethereum.remix-ide', // Your app's bundle ID
|
||||||
|
appPath: `${appOutDir}/${appName}.app`, // Path to your .app
|
||||||
|
appleId: process.env.APPLE_ID, // Your Apple ID
|
||||||
|
appleIdPassword: process.env.APPLE_ID_PASSWORD, // App-specific password
|
||||||
|
teamId: process.env.APPLE_TEAM_ID, // Your Apple Developer team ID (optional)
|
||||||
|
}) |
||||||
|
|
||||||
|
try { |
||||||
|
const r = await notarize({ |
||||||
|
appBundleId: 'org.ethereum.remix-ide', // Your app's bundle ID
|
||||||
|
appPath: `${appOutDir}/${appName}.app`, // Path to your .app
|
||||||
|
appleId: process.env.APPLE_ID, // Your Apple ID
|
||||||
|
appleIdPassword: process.env.APPLE_ID_PASSWORD, // App-specific password
|
||||||
|
teamId: process.env.APPLE_TEAM_ID, // Your Apple Developer team ID (optional)
|
||||||
|
}) |
||||||
|
|
||||||
|
console.log(r) |
||||||
|
|
||||||
|
// Stapling the app
|
||||||
|
console.log('STAPLING', `xcrun stapler staple "${appPath}"`) |
||||||
|
|
||||||
|
await execShellCommand(`xcrun stapler staple "${appPath}"`) |
||||||
|
|
||||||
|
} catch (error) { |
||||||
|
console.error('Error during notarization:', error) |
||||||
|
throw new Error('Error during notarization', error) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (!await checkStapleStatus()) { |
||||||
|
await runNotarize() |
||||||
|
await checkStapleStatus() |
||||||
|
} else { |
||||||
|
return [] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
{ |
||||||
|
"productName": "Remix-Desktop-alpha", |
||||||
|
"appId": "org.ethereum.remix-ide", |
||||||
|
"asar": true, |
||||||
|
"generateUpdatesFilesForAllChannels": false, |
||||||
|
"icon": "assets", |
||||||
|
"files": [ |
||||||
|
"build/**/*" |
||||||
|
], |
||||||
|
"afterSign": "aftersign.js", |
||||||
|
"afterAllArtifactBuild": "afterbuild.js", |
||||||
|
"publish": [ |
||||||
|
{ |
||||||
|
"provider": "github", |
||||||
|
"owner": "remix-project-org", |
||||||
|
"repo": "remix-desktop-alpha", |
||||||
|
"releaseType": "draft", |
||||||
|
"publishAutoUpdate": true |
||||||
|
} |
||||||
|
], |
||||||
|
"mac": { |
||||||
|
"category": "public.app-category.productivity", |
||||||
|
"icon": "assets/icon.png", |
||||||
|
"darkModeSupport": true, |
||||||
|
"hardenedRuntime": true, |
||||||
|
"gatekeeperAssess": false, |
||||||
|
"entitlements": "entitlements.mac.plist", |
||||||
|
"entitlementsInherit": "entitlements.mac.plist" |
||||||
|
}, |
||||||
|
"dmg": { |
||||||
|
"writeUpdateInfo": true, |
||||||
|
"sign": true |
||||||
|
}, |
||||||
|
"nsis": { |
||||||
|
"createDesktopShortcut": "always", |
||||||
|
"allowToChangeInstallationDirectory": true, |
||||||
|
"oneClick": false, |
||||||
|
"shortcutName": "Remix Desktop alpha", |
||||||
|
"differentialPackage": false |
||||||
|
}, |
||||||
|
"win": { |
||||||
|
"target": [ |
||||||
|
"nsis" |
||||||
|
], |
||||||
|
"artifactName": "${productName}-Setup-${version}.${ext}", |
||||||
|
"icon": "assets/icon.png" |
||||||
|
}, |
||||||
|
"deb": {}, |
||||||
|
"linux": { |
||||||
|
"target": [ |
||||||
|
"deb", |
||||||
|
"snap", |
||||||
|
"AppImage" |
||||||
|
], |
||||||
|
"category": "WebBrowser", |
||||||
|
"icon": "assets" |
||||||
|
}, |
||||||
|
"directories": { |
||||||
|
"output": "release" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
{ |
||||||
|
"productName": "Remix-Desktop-Beta", |
||||||
|
"appId": "org.ethereum.remix-ide", |
||||||
|
"asar": true, |
||||||
|
"generateUpdatesFilesForAllChannels": false, |
||||||
|
"icon": "assets", |
||||||
|
"files": [ |
||||||
|
"build/**/*" |
||||||
|
], |
||||||
|
"afterSign": "aftersign.js", |
||||||
|
"afterAllArtifactBuild": "afterbuild.js", |
||||||
|
"publish": [ |
||||||
|
{ |
||||||
|
"provider": "github", |
||||||
|
"owner": "remix-project-org", |
||||||
|
"repo": "remix-desktop-beta", |
||||||
|
"releaseType": "draft", |
||||||
|
"publishAutoUpdate": true |
||||||
|
} |
||||||
|
], |
||||||
|
"mac": { |
||||||
|
"category": "public.app-category.productivity", |
||||||
|
"icon": "assets/icon.png", |
||||||
|
"darkModeSupport": true, |
||||||
|
"hardenedRuntime": true, |
||||||
|
"gatekeeperAssess": false, |
||||||
|
"entitlements": "entitlements.mac.plist", |
||||||
|
"entitlementsInherit": "entitlements.mac.plist" |
||||||
|
}, |
||||||
|
"dmg": { |
||||||
|
"writeUpdateInfo": true, |
||||||
|
"sign": true |
||||||
|
}, |
||||||
|
"nsis": { |
||||||
|
"createDesktopShortcut": "always", |
||||||
|
"allowToChangeInstallationDirectory": true, |
||||||
|
"oneClick": false, |
||||||
|
"shortcutName": "Remix Desktop Beta", |
||||||
|
"differentialPackage": false |
||||||
|
}, |
||||||
|
"win": { |
||||||
|
"target": [ |
||||||
|
"nsis" |
||||||
|
], |
||||||
|
"artifactName": "Remix-Desktop-Setup-${version}.${ext}", |
||||||
|
"icon": "assets/icon.png" |
||||||
|
}, |
||||||
|
"deb": {}, |
||||||
|
"linux": { |
||||||
|
"target": [ |
||||||
|
"deb", |
||||||
|
"snap", |
||||||
|
"AppImage" |
||||||
|
], |
||||||
|
"category": "WebBrowser", |
||||||
|
"icon": "assets" |
||||||
|
}, |
||||||
|
"directories": { |
||||||
|
"output": "release" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||||
|
<plist version="1.0"> |
||||||
|
<dict> |
||||||
|
<key>com.apple.security.cs.allow-jit</key> |
||||||
|
<true/> |
||||||
|
<key>com.apple.security.cs.allow-unsigned-executable-memory</key> |
||||||
|
<true/> |
||||||
|
<key>com.apple.security.cs.allow-dyld-environment-variables</key> |
||||||
|
<true/> |
||||||
|
</dict> |
||||||
|
</plist> |
@ -0,0 +1,12 @@ |
|||||||
|
const esbuild = require('esbuild'); |
||||||
|
|
||||||
|
esbuild.build({ |
||||||
|
entryPoints: ['src/main.ts', 'src/preload.ts'], // Your TypeScript entry point
|
||||||
|
outdir: 'build', // Output bundled file
|
||||||
|
bundle: true, // Bundle all dependencies
|
||||||
|
platform: 'node', // Target Node.js platform
|
||||||
|
external: ['electron', 'fsevents', 'node-pty'], // Exclude native modules
|
||||||
|
target: ['node20'], // Match the Node.js version for Electron
|
||||||
|
tsconfig: 'tsconfig.json', // Your TypeScript config
|
||||||
|
minify: false, // Optional: Minify for production
|
||||||
|
}).catch(() => process.exit(1)); |
@ -0,0 +1,62 @@ |
|||||||
|
{ |
||||||
|
"productName": "Remix-Desktop-Insiders", |
||||||
|
"appId": "org.ethereum.remix-ide", |
||||||
|
"asar": true, |
||||||
|
"generateUpdatesFilesForAllChannels": false, |
||||||
|
"icon": "assets", |
||||||
|
"files": [ |
||||||
|
"build/**/*", |
||||||
|
"node_modules/node-pty/**/*" |
||||||
|
], |
||||||
|
"afterSign": "aftersign.js", |
||||||
|
"afterAllArtifactBuild": "afterbuild.js", |
||||||
|
"publish": [ |
||||||
|
{ |
||||||
|
"provider": "github", |
||||||
|
"owner": "remix-project-org", |
||||||
|
"repo": "remix-desktop-insiders", |
||||||
|
"releaseType": "draft", |
||||||
|
"publishAutoUpdate": true |
||||||
|
} |
||||||
|
], |
||||||
|
"mac": { |
||||||
|
"category": "public.app-category.productivity", |
||||||
|
"icon": "assets/icon.png", |
||||||
|
"darkModeSupport": true, |
||||||
|
"hardenedRuntime": true, |
||||||
|
"gatekeeperAssess": false, |
||||||
|
"entitlements": "entitlements.mac.plist", |
||||||
|
"entitlementsInherit": "entitlements.mac.plist" |
||||||
|
}, |
||||||
|
"dmg": { |
||||||
|
"writeUpdateInfo": true, |
||||||
|
"sign": true |
||||||
|
}, |
||||||
|
"nsis": { |
||||||
|
"createDesktopShortcut": "always", |
||||||
|
"allowToChangeInstallationDirectory": true, |
||||||
|
"oneClick": false, |
||||||
|
"shortcutName": "Remix Desktop Insiders", |
||||||
|
"differentialPackage": false |
||||||
|
}, |
||||||
|
"win": { |
||||||
|
"target": [ |
||||||
|
"nsis" |
||||||
|
], |
||||||
|
"artifactName": "Remix-Desktop-Setup-${version}.${ext}", |
||||||
|
"icon": "assets/icon.png" |
||||||
|
}, |
||||||
|
"deb": {}, |
||||||
|
"linux": { |
||||||
|
"target": [ |
||||||
|
"deb", |
||||||
|
"snap", |
||||||
|
"AppImage" |
||||||
|
], |
||||||
|
"category": "WebBrowser", |
||||||
|
"icon": "assets" |
||||||
|
}, |
||||||
|
"directories": { |
||||||
|
"output": "release" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
{ |
||||||
|
"productName": "Remix-Desktop", |
||||||
|
"appId": "org.ethereum.remix-ide", |
||||||
|
"asar": true, |
||||||
|
"generateUpdatesFilesForAllChannels": false, |
||||||
|
"icon": "assets", |
||||||
|
"files": [ |
||||||
|
"build/**/*" |
||||||
|
], |
||||||
|
"afterSign": "aftersign.js", |
||||||
|
"afterAllArtifactBuild": "afterbuild.js", |
||||||
|
"publish": [ |
||||||
|
{ |
||||||
|
"provider": "github", |
||||||
|
"owner": "remix-project-org", |
||||||
|
"repo": "remix-desktop", |
||||||
|
"releaseType": "draft", |
||||||
|
"publishAutoUpdate": true |
||||||
|
} |
||||||
|
], |
||||||
|
"mac": { |
||||||
|
"category": "public.app-category.productivity", |
||||||
|
"icon": "assets/icon.png", |
||||||
|
"darkModeSupport": true, |
||||||
|
"hardenedRuntime": true, |
||||||
|
"gatekeeperAssess": false, |
||||||
|
"entitlements": "entitlements.mac.plist", |
||||||
|
"entitlementsInherit": "entitlements.mac.plist" |
||||||
|
}, |
||||||
|
"dmg": { |
||||||
|
"writeUpdateInfo": true, |
||||||
|
"sign": true |
||||||
|
}, |
||||||
|
"nsis": { |
||||||
|
"createDesktopShortcut": "always", |
||||||
|
"allowToChangeInstallationDirectory": true, |
||||||
|
"oneClick": false, |
||||||
|
"shortcutName": "Remix Desktop", |
||||||
|
"differentialPackage": false |
||||||
|
}, |
||||||
|
"win": { |
||||||
|
"target": [ |
||||||
|
"nsis" |
||||||
|
], |
||||||
|
"artifactName": "${productName}-Setup-${version}.${ext}", |
||||||
|
"icon": "assets/icon.png" |
||||||
|
}, |
||||||
|
"deb": {}, |
||||||
|
"linux": { |
||||||
|
"target": [ |
||||||
|
"deb", |
||||||
|
"snap", |
||||||
|
"AppImage" |
||||||
|
], |
||||||
|
"category": "WebBrowser", |
||||||
|
"icon": "assets" |
||||||
|
}, |
||||||
|
"directories": { |
||||||
|
"output": "release" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,344 @@ |
|||||||
|
//
|
||||||
|
// Refer to the online docs for more details:
|
||||||
|
// https://nightwatchjs.org/guide/configuration/nightwatch-configuration-file.html
|
||||||
|
//
|
||||||
|
// _ _ _ _ _ _ _
|
||||||
|
// | \ | |(_) | | | | | | | |
|
||||||
|
// | \| | _ __ _ | |__ | |_ __ __ __ _ | |_ ___ | |__
|
||||||
|
// | . ` || | / _` || '_ \ | __|\ \ /\ / / / _` || __| / __|| '_ \
|
||||||
|
// | |\ || || (_| || | | || |_ \ V V / | (_| || |_ | (__ | | | |
|
||||||
|
// \_| \_/|_| \__, ||_| |_| \__| \_/\_/ \__,_| \__| \___||_| |_|
|
||||||
|
// __/ |
|
||||||
|
// |___/
|
||||||
|
//
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
// An array of folders (excluding subfolders) where your tests are located;
|
||||||
|
// if this is not specified, the test source must be passed as the second argument to the test runner.
|
||||||
|
src_folders: [], |
||||||
|
|
||||||
|
// See https://nightwatchjs.org/guide/concepts/page-object-model.html
|
||||||
|
page_objects_path: ['node_modules/nightwatch/examples/pages/'], |
||||||
|
|
||||||
|
// See https://nightwatchjs.org/guide/extending-nightwatch/adding-custom-commands.html
|
||||||
|
custom_commands_path: ['node_modules/nightwatch/examples/custom-commands/'], |
||||||
|
|
||||||
|
// See https://nightwatchjs.org/guide/extending-nightwatch/adding-custom-assertions.html
|
||||||
|
custom_assertions_path: '', |
||||||
|
|
||||||
|
// See https://nightwatchjs.org/guide/extending-nightwatch/adding-plugins.html
|
||||||
|
plugins: [], |
||||||
|
|
||||||
|
// See https://nightwatchjs.org/guide/concepts/test-globals.html#external-test-globals
|
||||||
|
globals_path : '', |
||||||
|
|
||||||
|
webdriver: {}, |
||||||
|
|
||||||
|
test_settings: { |
||||||
|
default: { |
||||||
|
disable_error_log: false, |
||||||
|
launch_url: 'https://nightwatchjs.org', |
||||||
|
|
||||||
|
screenshots: { |
||||||
|
enabled: false, |
||||||
|
path: 'screens', |
||||||
|
on_failure: true |
||||||
|
}, |
||||||
|
|
||||||
|
desiredCapabilities: { |
||||||
|
browserName : 'firefox' |
||||||
|
}, |
||||||
|
|
||||||
|
webdriver: { |
||||||
|
start_process: true, |
||||||
|
server_path: '' |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
firefox: { |
||||||
|
desiredCapabilities : { |
||||||
|
browserName : 'firefox', |
||||||
|
alwaysMatch: { |
||||||
|
acceptInsecureCerts: true, |
||||||
|
'moz:firefoxOptions': { |
||||||
|
args: [ |
||||||
|
// '-headless',
|
||||||
|
// '-verbose'
|
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
webdriver: { |
||||||
|
start_process: true, |
||||||
|
server_path: '', |
||||||
|
cli_args: [ |
||||||
|
// very verbose geckodriver logs
|
||||||
|
// '-vv'
|
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
chrome: { |
||||||
|
desiredCapabilities : { |
||||||
|
browserName : 'chrome', |
||||||
|
'goog:chromeOptions' : { |
||||||
|
// More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/
|
||||||
|
//
|
||||||
|
// w3c:false tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78)
|
||||||
|
w3c: true, |
||||||
|
args: [ |
||||||
|
//'--no-sandbox',
|
||||||
|
//'--ignore-certificate-errors',
|
||||||
|
//'--allow-insecure-localhost',
|
||||||
|
//'--headless'
|
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
webdriver: { |
||||||
|
start_process: true, |
||||||
|
server_path: '', |
||||||
|
cli_args: [ |
||||||
|
// --verbose
|
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
edge: { |
||||||
|
desiredCapabilities : { |
||||||
|
browserName : 'MicrosoftEdge', |
||||||
|
'ms:edgeOptions' : { |
||||||
|
w3c: true, |
||||||
|
// More info on EdgeDriver: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options
|
||||||
|
args: [ |
||||||
|
//'--headless'
|
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
webdriver: { |
||||||
|
start_process: true, |
||||||
|
// Download msedgedriver from https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/
|
||||||
|
// and set the location below:
|
||||||
|
server_path: '', |
||||||
|
cli_args: [ |
||||||
|
// --verbose
|
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Configuration for when using cucumber-js (https://cucumber.io) |
|
||||||
|
// |
|
||||||
|
// It uses the bundled examples inside the nightwatch examples folder; feel free |
|
||||||
|
// to adapt this to your own project needs |
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
'cucumber-js': { |
||||||
|
src_folders: ['examples/cucumber-js/features/step_definitions'], |
||||||
|
|
||||||
|
test_runner: { |
||||||
|
// set cucumber as the runner
|
||||||
|
type: 'cucumber', |
||||||
|
|
||||||
|
// define cucumber specific options
|
||||||
|
options: { |
||||||
|
//set the feature path
|
||||||
|
feature_path: 'node_modules/nightwatch/examples/cucumber-js/*/*.feature', |
||||||
|
|
||||||
|
// start the webdriver session automatically (enabled by default)
|
||||||
|
// auto_start_session: true
|
||||||
|
|
||||||
|
// use parallel execution in Cucumber
|
||||||
|
// parallel: 2 // set number of workers to use (can also be defined in the cli as --parallel 2
|
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Configuration for when using the browserstack.com cloud service |
|
||||||
|
// |
|
||||||
|
// Please set the username and access key by setting the environment variables: |
|
||||||
|
// - BROWSERSTACK_USERNAME |
|
||||||
|
// - BROWSERSTACK_ACCESS_KEY |
|
||||||
|
// .env files are supported |
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
browserstack: { |
||||||
|
selenium: { |
||||||
|
host: 'hub.browserstack.com', |
||||||
|
port: 443 |
||||||
|
}, |
||||||
|
// More info on configuring capabilities can be found on:
|
||||||
|
// https://www.browserstack.com/automate/capabilities?tag=selenium-4
|
||||||
|
desiredCapabilities: { |
||||||
|
'bstack:options' : { |
||||||
|
userName: '${BROWSERSTACK_USERNAME}', |
||||||
|
accessKey: '${BROWSERSTACK_ACCESS_KEY}', |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
disable_error_log: true, |
||||||
|
webdriver: { |
||||||
|
timeout_options: { |
||||||
|
timeout: 15000, |
||||||
|
retry_attempts: 3 |
||||||
|
}, |
||||||
|
keep_alive: true, |
||||||
|
start_process: false |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
'browserstack.local': { |
||||||
|
extends: 'browserstack', |
||||||
|
desiredCapabilities: { |
||||||
|
'browserstack.local': true |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
'browserstack.chrome': { |
||||||
|
extends: 'browserstack', |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'chrome', |
||||||
|
chromeOptions : { |
||||||
|
w3c: true |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
'browserstack.firefox': { |
||||||
|
extends: 'browserstack', |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'firefox' |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
'browserstack.ie': { |
||||||
|
extends: 'browserstack', |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'internet explorer', |
||||||
|
browserVersion: '11.0' |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
'browserstack.safari': { |
||||||
|
extends: 'browserstack', |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'safari' |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
'browserstack.local_chrome': { |
||||||
|
extends: 'browserstack.local', |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'chrome' |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
'browserstack.local_firefox': { |
||||||
|
extends: 'browserstack.local', |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'firefox' |
||||||
|
} |
||||||
|
}, |
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Configuration for when using the SauceLabs cloud service |
|
||||||
|
// |
|
||||||
|
// Please set the username and access key by setting the environment variables: |
|
||||||
|
// - SAUCE_USERNAME |
|
||||||
|
// - SAUCE_ACCESS_KEY |
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
saucelabs: { |
||||||
|
selenium: { |
||||||
|
host: 'ondemand.saucelabs.com', |
||||||
|
port: 443 |
||||||
|
}, |
||||||
|
// More info on configuring capabilities can be found on:
|
||||||
|
// https://docs.saucelabs.com/dev/test-configuration-options/
|
||||||
|
desiredCapabilities: { |
||||||
|
'sauce:options' : { |
||||||
|
username: '${SAUCE_USERNAME}', |
||||||
|
accessKey: '${SAUCE_ACCESS_KEY}', |
||||||
|
screenResolution: '1280x1024' |
||||||
|
// https://docs.saucelabs.com/dev/cli/sauce-connect-proxy/#--region
|
||||||
|
// region: 'us-west-1'
|
||||||
|
// https://docs.saucelabs.com/dev/test-configuration-options/#tunnelidentifier
|
||||||
|
// parentTunnel: '',
|
||||||
|
// tunnelIdentifier: '',
|
||||||
|
} |
||||||
|
}, |
||||||
|
disable_error_log: false, |
||||||
|
webdriver: { |
||||||
|
start_process: false |
||||||
|
} |
||||||
|
}, |
||||||
|
'saucelabs.chrome': { |
||||||
|
extends: 'saucelabs', |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'chrome', |
||||||
|
browserVersion: 'latest', |
||||||
|
javascriptEnabled: true, |
||||||
|
acceptSslCerts: true, |
||||||
|
timeZone: 'London', |
||||||
|
chromeOptions : { |
||||||
|
w3c: true |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
'saucelabs.firefox': { |
||||||
|
extends: 'saucelabs', |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'firefox', |
||||||
|
browserVersion: 'latest', |
||||||
|
javascriptEnabled: true, |
||||||
|
acceptSslCerts: true, |
||||||
|
timeZone: 'London' |
||||||
|
} |
||||||
|
}, |
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Configuration for when using the Selenium service, either locally or remote, |
|
||||||
|
// like Selenium Grid |
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
selenium_server: { |
||||||
|
// Selenium Server is running locally and is managed by Nightwatch
|
||||||
|
// Install the NPM package @nightwatch/selenium-server or download the selenium server jar file from https://github.com/SeleniumHQ/selenium/releases/, e.g.: selenium-server-4.1.1.jar
|
||||||
|
selenium: { |
||||||
|
start_process: true, |
||||||
|
port: 4444, |
||||||
|
server_path: '', // Leave empty if @nightwatch/selenium-server is installed
|
||||||
|
command: 'standalone', // Selenium 4 only
|
||||||
|
cli_args: { |
||||||
|
//'webdriver.gecko.driver': '',
|
||||||
|
//'webdriver.chrome.driver': ''
|
||||||
|
} |
||||||
|
}, |
||||||
|
webdriver: { |
||||||
|
start_process: false, |
||||||
|
default_path_prefix: '/wd/hub' |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
'selenium.chrome': { |
||||||
|
extends: 'selenium_server', |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'chrome', |
||||||
|
chromeOptions : { |
||||||
|
w3c: true |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
'selenium.firefox': { |
||||||
|
extends: 'selenium_server', |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'firefox', |
||||||
|
'moz:firefoxOptions': { |
||||||
|
args: [ |
||||||
|
// '-headless',
|
||||||
|
// '-verbose'
|
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,39 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
# Path to the JSON file containing the DMG paths |
||||||
|
JSON_FILE="dmgs.json" |
||||||
|
|
||||||
|
# Read the DMGs array from the JSON file |
||||||
|
DMG_PATHS=$(jq -r '.dmgs[]' "$JSON_FILE") |
||||||
|
|
||||||
|
echo $DMG_PATHS |
||||||
|
|
||||||
|
xcrun notarytool store-credentials "notarytool-password" \ |
||||||
|
--apple-id ${APPLE_ID} \ |
||||||
|
--team-id ${APPLE_TEAM_ID} \ |
||||||
|
--password ${APPLE_ID_PASSWORD} || exit 1 |
||||||
|
|
||||||
|
# Use jq to parse the DMGs array and read each line |
||||||
|
while IFS= read -r DMG_PATH; do |
||||||
|
# Remove single quotes from the path if present |
||||||
|
DMG_PATH_CLEANED=$(echo $DMG_PATH | tr -d "'") |
||||||
|
|
||||||
|
echo "Submitting $DMG_PATH_CLEANED for notarization..." |
||||||
|
|
||||||
|
# Replace `your-app-specific-args` with the actual arguments for your app |
||||||
|
# Ensure your notarytool command and arguments are correct for your application |
||||||
|
xcrun notarytool submit "$DMG_PATH_CLEANED" --keychain-profile "notarytool-password" --wait |
||||||
|
|
||||||
|
# Check the command's success |
||||||
|
if [ $? -eq 0 ]; then |
||||||
|
echo "Successfully submitted $DMG_PATH_CLEANED for notarization." |
||||||
|
xcrun stapler staple "$DMG_PATH_CLEANED" |
||||||
|
echo "Successfully stapled $DMG_PATH_CLEANED." |
||||||
|
spctl -a -t open -vvv --context context:primary-signature "$DMG_PATH_CLEANED" |
||||||
|
echo "Successfully checked $DMG_PATH_CLEANED." |
||||||
|
else |
||||||
|
echo "Failed to submit $DMG_PATH_CLEANED for notarization." |
||||||
|
fi |
||||||
|
done < <(jq -r '.dmgs[]' "$JSON_FILE") |
||||||
|
|
||||||
|
echo "All DMG submissions completed." |
@ -0,0 +1,19 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
set -e |
||||||
|
TEST_EXITCODE=0 |
||||||
|
yarn run build:e2e && node ./splice_tests.js |
||||||
|
TESTFILES=$(node ./splice_tests.js | circleci tests split --split-by=timings) |
||||||
|
for TESTFILE in $TESTFILES; do |
||||||
|
yarn run test --test ./build-e2e/remixdesktop/test/tests/app/${TESTFILE} || yarn run test --test ./build-e2e/remixdesktop/test/tests/app/${TESTFILE} || TEST_EXITCODE=1 |
||||||
|
done |
||||||
|
|
||||||
|
|
||||||
|
if [ "$CIRCLE_NODE_INDEX" -eq 1 ]; then |
||||||
|
yarn test:offline || TEST_EXITCODE=1 |
||||||
|
fi |
||||||
|
|
||||||
|
echo "$TEST_EXITCODE" |
||||||
|
if [ "$TEST_EXITCODE" -eq 1 ] |
||||||
|
then |
||||||
|
exit 1 |
||||||
|
fi |
@ -0,0 +1,14 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
set -e |
||||||
|
TEST_EXITCODE=0 |
||||||
|
yarn run build:e2e && node ./splice_tests.js |
||||||
|
TESTFILES=$(node ./splice_tests.js | grep -i 'git' | circleci tests split --split-by=timings) |
||||||
|
for TESTFILE in $TESTFILES; do |
||||||
|
yarn run test --use-isogit --test ./build-e2e/remixdesktop/test/tests/app/${TESTFILE} || yarn run test --use-isogit --test ./build-e2e/remixdesktop/test/tests/app/${TESTFILE} || TEST_EXITCODE=1 |
||||||
|
done |
||||||
|
|
||||||
|
echo "$TEST_EXITCODE" |
||||||
|
if [ "$TEST_EXITCODE" -eq 1 ] |
||||||
|
then |
||||||
|
exit 1 |
||||||
|
fi |
@ -0,0 +1,24 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
# Read the version from package.json |
||||||
|
version=$(awk -F'"' '/"version":/ {print $4}' package.json) |
||||||
|
|
||||||
|
# Determine the command to run based on the version |
||||||
|
if [[ $version == *"beta"* ]]; then |
||||||
|
command="yarn dist -c beta.json" |
||||||
|
elif [[ $version == *"alpha"* ]]; then |
||||||
|
command="yarn dist -c alpha.json" |
||||||
|
elif [[ $version == *"insiders"* ]]; then |
||||||
|
command="yarn dist -c insiders.json" |
||||||
|
else |
||||||
|
command="yarn dist -c latest.json" |
||||||
|
fi |
||||||
|
|
||||||
|
# Append any arguments passed in CLI |
||||||
|
for arg in "$@"; do |
||||||
|
command+=" $arg" |
||||||
|
done |
||||||
|
|
||||||
|
# Print and run the command |
||||||
|
echo "Running command: $command" |
||||||
|
$command |
@ -0,0 +1,24 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
# Read the version from package.json |
||||||
|
version=$(awk -F'"' '/"version":/ {print $4}' package.json) |
||||||
|
|
||||||
|
# Determine the command to run based on the version |
||||||
|
if [[ $version == *"beta"* ]]; then |
||||||
|
command="yarn esbuild -c beta.json" |
||||||
|
elif [[ $version == *"alpha"* ]]; then |
||||||
|
command="yarn esbuild -c alpha.json" |
||||||
|
elif [[ $version == *"insiders"* ]]; then |
||||||
|
command="yarn esbuild -c insiders.json" |
||||||
|
else |
||||||
|
command="yarn esbuild -c latest.json" |
||||||
|
fi |
||||||
|
|
||||||
|
# Append any arguments passed in CLI |
||||||
|
for arg in "$@"; do |
||||||
|
command+=" $arg" |
||||||
|
done |
||||||
|
|
||||||
|
# Print and run the command |
||||||
|
echo "Running command: $command" |
||||||
|
$command |
@ -0,0 +1,24 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
# Read the version from package.json |
||||||
|
version=$(awk -F'"' '/"version":/ {print $4}' package.json) |
||||||
|
|
||||||
|
# Determine the command to run based on the version |
||||||
|
if [[ $version == *"beta"* ]]; then |
||||||
|
command="yarn tscbuild -c beta.json" |
||||||
|
elif [[ $version == *"alpha"* ]]; then |
||||||
|
command="yarn tscbuild -c alpha.json" |
||||||
|
elif [[ $version == *"insiders"* ]]; then |
||||||
|
command="yarn tscbuild -c insiders.json" |
||||||
|
else |
||||||
|
command="yarn tscbuild -c latest.json" |
||||||
|
fi |
||||||
|
|
||||||
|
# Append any arguments passed in CLI |
||||||
|
for arg in "$@"; do |
||||||
|
command+=" $arg" |
||||||
|
done |
||||||
|
|
||||||
|
# Print and run the command |
||||||
|
echo "Running command: $command" |
||||||
|
$command |
@ -0,0 +1,24 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
# Read the version from package.json |
||||||
|
version=$(awk -F'"' '/"version":/ {print $4}' package.json) |
||||||
|
|
||||||
|
# Determine the command to run based on the version |
||||||
|
if [[ $version == *"beta"* ]]; then |
||||||
|
command="yarn dist -c beta.json" |
||||||
|
elif [[ $version == *"alpha"* ]]; then |
||||||
|
command="yarn dist -c alpha.json" |
||||||
|
elif [[ $version == *"insiders"* ]]; then |
||||||
|
command="yarn dist -c insiders.json" |
||||||
|
else |
||||||
|
command="yarn dist -c latest.json" |
||||||
|
fi |
||||||
|
|
||||||
|
# Append any arguments passed in CLI |
||||||
|
for arg in "$@"; do |
||||||
|
command+=" $arg" |
||||||
|
done |
||||||
|
|
||||||
|
# Print and run the command |
||||||
|
echo "Running command: $command" |
||||||
|
$command |
@ -0,0 +1,35 @@ |
|||||||
|
const fs = require('fs'); |
||||||
|
const path = require('path'); |
||||||
|
|
||||||
|
// Directory to read files from
|
||||||
|
const testDirectory = './build-e2e/remixdesktop/test/tests/app/'; |
||||||
|
|
||||||
|
// Function to read files in a directory and return their paths
|
||||||
|
function getTestFiles(directory) { |
||||||
|
return fs.readdirSync(directory) |
||||||
|
.filter(file => file.endsWith('.test.js')) // Get only .test.js files
|
||||||
|
.map(file => path.join(directory, file)); // Return full path of each file
|
||||||
|
} |
||||||
|
|
||||||
|
// Function to check if a file contains a specific word
|
||||||
|
function fileContainsWord(filePath, word) { |
||||||
|
const content = fs.readFileSync(filePath, 'utf-8'); // Read file content
|
||||||
|
return content.includes(word); // Check if word is in content
|
||||||
|
} |
||||||
|
|
||||||
|
// Function to filter out files that do not contain the specified word
|
||||||
|
function filterFilesByWord(files, word) { |
||||||
|
return files.filter(file => fileContainsWord(file, word)); // Return files that do not contain the word
|
||||||
|
} |
||||||
|
|
||||||
|
// Get all test files in the specified directory
|
||||||
|
const testFiles = getTestFiles(testDirectory); |
||||||
|
|
||||||
|
// Filter out files that do not contain "@offline"
|
||||||
|
const filteredFiles = filterFilesByWord(testFiles, ''); |
||||||
|
|
||||||
|
// Output the list of filtered files
|
||||||
|
//console.log('Files without "@offline":', filteredFiles);
|
||||||
|
for (let i = 0; i < filteredFiles.length; i++) { |
||||||
|
console.log(path.basename(filteredFiles[i])); |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
import { ElectronBasePluginClient } from "@remixproject/plugin-electron"; |
||||||
|
import { Profile } from "@remixproject/plugin-utils"; |
||||||
|
|
||||||
|
export class ElectronBasePluginRemixdClient extends ElectronBasePluginClient { |
||||||
|
log: (...message: any) => void |
||||||
|
error: (...message: any) => void |
||||||
|
|
||||||
|
currentSharedFolder: string = '' |
||||||
|
constructor(webContentsId: number, profile: Profile) { |
||||||
|
super(webContentsId, profile); |
||||||
|
this.log = (...message: any) => { |
||||||
|
for(const m of message) { |
||||||
|
this.call('terminal', 'log', { |
||||||
|
type: 'log', |
||||||
|
value: m |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
this.error = (...message: any) => { |
||||||
|
for(const m of message) { |
||||||
|
this.call('terminal', 'log', { |
||||||
|
type: 'error', |
||||||
|
value: m |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
this.onload(async () => { |
||||||
|
this.on('fs' as any, 'workingDirChanged', async (path: string) => { |
||||||
|
console.log('workingDirChanged base remixd', path) |
||||||
|
this.currentSharedFolder = path |
||||||
|
}) |
||||||
|
this.currentSharedFolder = await this.call('fs' as any, 'getWorkingDir') |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
import * as pathModule from 'path' |
||||||
|
/** |
||||||
|
* returns the absolute path of the given @arg path |
||||||
|
* |
||||||
|
* @param {String} path - relative path (Unix style which is the one used by Remix IDE) |
||||||
|
* @param {String} sharedFolder - absolute shared path. platform dependent representation. |
||||||
|
* @return {String} platform dependent absolute path (/home/user1/.../... for unix, c:\user\...\... for windows) |
||||||
|
*/ |
||||||
|
function absolutePath (path: string, sharedFolder:string): string { |
||||||
|
path = normalizePath(path) |
||||||
|
path = pathModule.resolve(sharedFolder, path) |
||||||
|
return path |
||||||
|
} |
||||||
|
function normalizePath (path) { |
||||||
|
if (path === '/') path = './' |
||||||
|
if (process.platform === 'win32') { |
||||||
|
return path.replace(/\//g, '\\') |
||||||
|
} |
||||||
|
return path |
||||||
|
} |
||||||
|
|
||||||
|
export { absolutePath, normalizePath } |
||||||
|
|
||||||
|
|
@ -0,0 +1,122 @@ |
|||||||
|
import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" |
||||||
|
import { Profile } from "@remixproject/plugin-utils" |
||||||
|
import { autoUpdater } from "electron-updater" |
||||||
|
import { app } from 'electron'; |
||||||
|
import { isE2E } from "../main"; |
||||||
|
import { trackEvent } from "../utils/matamo"; |
||||||
|
|
||||||
|
const profile = { |
||||||
|
displayName: 'appUpdater', |
||||||
|
name: 'appUpdater', |
||||||
|
description: 'appUpdater', |
||||||
|
} |
||||||
|
|
||||||
|
export class AppUpdaterPlugin extends ElectronBasePlugin { |
||||||
|
clients: AppUpdaterPluginClient[] = [] |
||||||
|
constructor() { |
||||||
|
super(profile, clientProfile, AppUpdaterPluginClient) |
||||||
|
this.methods = [...super.methods] |
||||||
|
|
||||||
|
autoUpdater.autoDownload = false |
||||||
|
autoUpdater.disableDifferentialDownload = true |
||||||
|
|
||||||
|
autoUpdater.on('checking-for-update', () => { |
||||||
|
console.log('Checking for update...'); |
||||||
|
this.sendToLog('Checking for update...') |
||||||
|
}) |
||||||
|
autoUpdater.on('update-available', (info: any) => { |
||||||
|
console.log('Update available.', info); |
||||||
|
this.sendToLog('Update available.') |
||||||
|
for (const client of this.clients) { |
||||||
|
client.askForUpdate() |
||||||
|
} |
||||||
|
}) |
||||||
|
autoUpdater.on('update-not-available', () => { |
||||||
|
console.log('Update not available.'); |
||||||
|
this.sendToLog('App is already up to date.') |
||||||
|
|
||||||
|
}) |
||||||
|
autoUpdater.on('error', (err) => { |
||||||
|
console.log('Error in auto-updater. ' + err); |
||||||
|
this.sendToLog('Cannot find updates...') |
||||||
|
}) |
||||||
|
autoUpdater.on('download-progress', (progressObj) => { |
||||||
|
let log_message = "Download speed: " + progressObj.bytesPerSecond; |
||||||
|
log_message = log_message + ' - Downloaded ' + progressObj.percent + '%'; |
||||||
|
log_message = log_message + ' (' + progressObj.transferred + "/" + progressObj.total + ')'; |
||||||
|
console.log(log_message); |
||||||
|
this.sendToLog(log_message) |
||||||
|
}) |
||||||
|
autoUpdater.on('update-downloaded', (info) => { |
||||||
|
console.log('Update downloaded'); |
||||||
|
this.sendToLog('Update downloaded') |
||||||
|
this.sendToLog('processing download... please wait...') |
||||||
|
for(const client of this.clients) { |
||||||
|
client.downloadReady() |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
async sendToLog(message: string): Promise<void> { |
||||||
|
for (const client of this.clients) { |
||||||
|
client.call('terminal', 'log', { |
||||||
|
type: 'log', |
||||||
|
value: message, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const clientProfile: Profile = { |
||||||
|
name: 'appUpdater', |
||||||
|
displayName: 'appUpdater', |
||||||
|
description: 'appUpdater', |
||||||
|
methods: ['checkForUpdates', 'download', 'install'], |
||||||
|
} |
||||||
|
|
||||||
|
class AppUpdaterPluginClient extends ElectronBasePluginClient { |
||||||
|
constructor(webContentsId: number, profile: Profile) { |
||||||
|
super(webContentsId, profile) |
||||||
|
} |
||||||
|
|
||||||
|
async onActivation(): Promise<void> { |
||||||
|
this.onload(async () => { |
||||||
|
this.emit('loaded') |
||||||
|
if(isE2E) return |
||||||
|
await this.checkForUpdates() |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
async askForUpdate(): Promise<void> { |
||||||
|
this.emit('askForUpdate') |
||||||
|
} |
||||||
|
|
||||||
|
async downloadReady(): Promise<void> { |
||||||
|
// we do a wait here to make sure that the download is done, it's a bug in electron-updater
|
||||||
|
setTimeout(() => { |
||||||
|
this.emit('downloadReady') |
||||||
|
} |
||||||
|
, 10000) |
||||||
|
} |
||||||
|
|
||||||
|
async download(): Promise<void> { |
||||||
|
autoUpdater.downloadUpdate() |
||||||
|
} |
||||||
|
|
||||||
|
async install(): Promise<void> { |
||||||
|
autoUpdater.quitAndInstall() |
||||||
|
} |
||||||
|
|
||||||
|
async checkForUpdates(): Promise<void> { |
||||||
|
console.log('checkForUpdates') |
||||||
|
this.call('terminal', 'log', { |
||||||
|
type: 'log', |
||||||
|
value: 'Remix Desktop version: ' + autoUpdater.currentVersion, |
||||||
|
}) |
||||||
|
trackEvent('App', 'CheckForUpdate', 'Remix Desktop version: ' + autoUpdater.currentVersion, 1); |
||||||
|
|
||||||
|
autoUpdater.checkForUpdates() |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,248 @@ |
|||||||
|
import { Profile } from "@remixproject/plugin-utils"; |
||||||
|
import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" |
||||||
|
import chokidar from 'chokidar' |
||||||
|
import { ElectronBasePluginRemixdClient } from "../lib/remixd" |
||||||
|
import fs from 'fs' |
||||||
|
import * as utils from '../lib/utils' |
||||||
|
|
||||||
|
import { basename, join } from "path"; |
||||||
|
import { spawn } from "child_process"; |
||||||
|
const profile: Profile = { |
||||||
|
name: 'foundry', |
||||||
|
displayName: 'electron foundry', |
||||||
|
description: 'electron foundry', |
||||||
|
} |
||||||
|
|
||||||
|
export class FoundryPlugin extends ElectronBasePlugin { |
||||||
|
clients: any[] |
||||||
|
constructor() { |
||||||
|
super(profile, clientProfile, FoundryPluginClient) |
||||||
|
this.methods = [...super.methods] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const clientProfile: Profile = { |
||||||
|
name: 'foundry', |
||||||
|
displayName: 'electron foundry', |
||||||
|
description: 'electron foundry', |
||||||
|
methods: ['sync', 'compile'] |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
class FoundryPluginClient extends ElectronBasePluginRemixdClient { |
||||||
|
|
||||||
|
watcher: chokidar.FSWatcher |
||||||
|
warnlog: boolean |
||||||
|
buildPath: string |
||||||
|
cachePath: string |
||||||
|
logTimeout: NodeJS.Timeout |
||||||
|
processingTimeout: NodeJS.Timeout |
||||||
|
|
||||||
|
async onActivation(): Promise<void> { |
||||||
|
console.log('Foundry plugin activated') |
||||||
|
this.call('terminal', 'log', { type: 'log', value: 'Foundry plugin activated' }) |
||||||
|
this.on('fs' as any, 'workingDirChanged', async (path: string) => { |
||||||
|
console.log('workingDirChanged foundry', path) |
||||||
|
this.currentSharedFolder = path |
||||||
|
this.startListening() |
||||||
|
}) |
||||||
|
this.currentSharedFolder = await this.call('fs' as any, 'getWorkingDir') |
||||||
|
if(this.currentSharedFolder) this.startListening() |
||||||
|
} |
||||||
|
|
||||||
|
startListening() { |
||||||
|
this.buildPath = utils.absolutePath('out', this.currentSharedFolder) |
||||||
|
this.cachePath = utils.absolutePath('cache', this.currentSharedFolder) |
||||||
|
console.log('Foundry plugin checking for', this.buildPath, this.cachePath) |
||||||
|
if (fs.existsSync(this.buildPath) && fs.existsSync(this.cachePath)) { |
||||||
|
this.listenOnFoundryCompilation() |
||||||
|
} else { |
||||||
|
this.listenOnFoundryFolder() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
listenOnFoundryFolder() { |
||||||
|
console.log('Foundry out folder doesn\'t exist... waiting for the compilation.') |
||||||
|
try { |
||||||
|
if (this.watcher) this.watcher.close() |
||||||
|
this.watcher = chokidar.watch(this.currentSharedFolder, { depth: 1, ignorePermissionErrors: true, ignoreInitial: true }) |
||||||
|
// watch for new folders
|
||||||
|
this.watcher.on('addDir', (path: string) => { |
||||||
|
console.log('add dir foundry', path) |
||||||
|
if (fs.existsSync(this.buildPath) && fs.existsSync(this.cachePath)) { |
||||||
|
this.listenOnFoundryCompilation() |
||||||
|
} |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
compile() { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const cmd = `forge build` |
||||||
|
const options = { cwd: this.currentSharedFolder, shell: true } |
||||||
|
const child = spawn(cmd, options) |
||||||
|
let result = '' |
||||||
|
let error = '' |
||||||
|
child.stdout.on('data', (data) => { |
||||||
|
const msg = `[Foundry Compilation]: ${data.toString()}` |
||||||
|
console.log('\x1b[32m%s\x1b[0m', msg) |
||||||
|
result += msg + '\n' |
||||||
|
}) |
||||||
|
child.stderr.on('data', (err) => { |
||||||
|
error += `[Foundry Compilation]: ${err.toString()} \n` |
||||||
|
}) |
||||||
|
child.on('close', () => { |
||||||
|
if (error && result) resolve(error + result) |
||||||
|
else if (error) reject(error) |
||||||
|
else resolve(result) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
checkPath() { |
||||||
|
if (!fs.existsSync(this.buildPath) || !fs.existsSync(this.cachePath)) { |
||||||
|
this.listenOnFoundryFolder() |
||||||
|
return false |
||||||
|
} |
||||||
|
if (!fs.existsSync(join(this.cachePath, 'solidity-files-cache.json'))) return false |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
private async processArtifact() { |
||||||
|
if (!this.checkPath()) return |
||||||
|
const folderFiles = await fs.promises.readdir(this.buildPath) // "out" folder
|
||||||
|
try { |
||||||
|
const cache = JSON.parse(await fs.promises.readFile(join(this.cachePath, 'solidity-files-cache.json'), { encoding: 'utf-8' })) |
||||||
|
// name of folders are file names
|
||||||
|
for (const file of folderFiles) { |
||||||
|
const path = join(this.buildPath, file) // out/Counter.sol/
|
||||||
|
const compilationResult = { |
||||||
|
input: {}, |
||||||
|
output: { |
||||||
|
contracts: {}, |
||||||
|
sources: {} |
||||||
|
}, |
||||||
|
inputSources: { sources: {}, target: '' }, |
||||||
|
solcVersion: null, |
||||||
|
compilationTarget: null |
||||||
|
} |
||||||
|
compilationResult.inputSources.target = file |
||||||
|
await this.readContract(path, compilationResult, cache) |
||||||
|
this.emit('compilationFinished', compilationResult.compilationTarget, { sources: compilationResult.input }, 'soljson', compilationResult.output, compilationResult.solcVersion) |
||||||
|
} |
||||||
|
|
||||||
|
clearTimeout(this.logTimeout) |
||||||
|
this.logTimeout = setTimeout(() => { |
||||||
|
// @ts-ignore
|
||||||
|
this.call('terminal', 'log', { type: 'log', value: `receiving compilation result from Foundry. Select a file to populate the contract interaction interface.` }) |
||||||
|
console.log('Syncing compilation result from Foundry') |
||||||
|
}, 1000) |
||||||
|
|
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async triggerProcessArtifact() { |
||||||
|
// prevent multiple calls
|
||||||
|
clearTimeout(this.processingTimeout) |
||||||
|
this.processingTimeout = setTimeout(async () => await this.processArtifact(), 1000) |
||||||
|
} |
||||||
|
|
||||||
|
listenOnFoundryCompilation() { |
||||||
|
try { |
||||||
|
console.log('Foundry out folder exists... processing the artifact.') |
||||||
|
if (this.watcher) this.watcher.close() |
||||||
|
this.watcher = chokidar.watch(this.cachePath, { depth: 0, ignorePermissionErrors: true, ignoreInitial: true }) |
||||||
|
this.watcher.on('change', async () => await this.triggerProcessArtifact()) |
||||||
|
this.watcher.on('add', async () => await this.triggerProcessArtifact()) |
||||||
|
this.watcher.on('unlink', async () => await this.triggerProcessArtifact()) |
||||||
|
// process the artifact on activation
|
||||||
|
this.triggerProcessArtifact() |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async readContract(contractFolder, compilationResultPart, cache) { |
||||||
|
const files = await fs.promises.readdir(contractFolder) |
||||||
|
for (const file of files) { |
||||||
|
const path = join(contractFolder, file) |
||||||
|
const content = await fs.promises.readFile(path, { encoding: 'utf-8' }) |
||||||
|
compilationResultPart.inputSources.sources[file] = { content } |
||||||
|
await this.feedContractArtifactFile(file, content, compilationResultPart, cache) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async feedContractArtifactFile(path, content, compilationResultPart, cache) { |
||||||
|
const contentJSON = JSON.parse(content) |
||||||
|
const contractName = basename(path).replace('.json', '') |
||||||
|
|
||||||
|
let sourcePath = '' |
||||||
|
if (contentJSON?.metadata?.settings?.compilationTarget) { |
||||||
|
for (const key in contentJSON.metadata.settings.compilationTarget) { |
||||||
|
if (contentJSON.metadata.settings.compilationTarget[key] === contractName) { |
||||||
|
sourcePath = key |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!sourcePath) return |
||||||
|
|
||||||
|
const currentCache = cache.files[sourcePath] |
||||||
|
if (!currentCache.artifacts[contractName]) return |
||||||
|
|
||||||
|
// extract source and version
|
||||||
|
const metadata = contentJSON.metadata |
||||||
|
if (metadata.compiler && metadata.compiler.version) { |
||||||
|
compilationResultPart.solcVersion = metadata.compiler.version |
||||||
|
} else { |
||||||
|
compilationResultPart.solcVersion = '' |
||||||
|
console.log('\x1b[32m%s\x1b[0m', 'compiler version not found, please update Foundry to the latest version.') |
||||||
|
} |
||||||
|
|
||||||
|
if (metadata.sources) { |
||||||
|
for (const path in metadata.sources) { |
||||||
|
const absPath = utils.absolutePath(path, this.currentSharedFolder) |
||||||
|
try { |
||||||
|
const content = await fs.promises.readFile(absPath, { encoding: 'utf-8' }) |
||||||
|
compilationResultPart.input[path] = { content } |
||||||
|
} catch (e) { |
||||||
|
compilationResultPart.input[path] = { content: '' } |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
console.log('\x1b[32m%s\x1b[0m', 'sources input not found, please update Foundry to the latest version.') |
||||||
|
} |
||||||
|
|
||||||
|
compilationResultPart.compilationTarget = sourcePath |
||||||
|
// extract data
|
||||||
|
if (!compilationResultPart.output['sources'][sourcePath]) compilationResultPart.output['sources'][sourcePath] = {} |
||||||
|
compilationResultPart.output['sources'][sourcePath] = { |
||||||
|
ast: contentJSON['ast'], |
||||||
|
id: contentJSON['id'] |
||||||
|
} |
||||||
|
if (!compilationResultPart.output['contracts'][sourcePath]) compilationResultPart.output['contracts'][sourcePath] = {} |
||||||
|
|
||||||
|
contentJSON.bytecode.object = contentJSON.bytecode.object.replace('0x', '') |
||||||
|
contentJSON.deployedBytecode.object = contentJSON.deployedBytecode.object.replace('0x', '') |
||||||
|
compilationResultPart.output['contracts'][sourcePath][contractName] = { |
||||||
|
abi: contentJSON.abi, |
||||||
|
evm: { |
||||||
|
bytecode: contentJSON.bytecode, |
||||||
|
deployedBytecode: contentJSON.deployedBytecode, |
||||||
|
methodIdentifiers: contentJSON.methodIdentifiers |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async sync() { |
||||||
|
console.log('syncing Foundry with Remix...') |
||||||
|
this.processArtifact() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,220 @@ |
|||||||
|
import { Profile } from "@remixproject/plugin-utils"; |
||||||
|
import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" |
||||||
|
import chokidar from 'chokidar' |
||||||
|
import { ElectronBasePluginRemixdClient } from "../lib/remixd" |
||||||
|
import fs from 'fs' |
||||||
|
import * as utils from '../lib/utils' |
||||||
|
|
||||||
|
import { basename, join } from "path"; |
||||||
|
import { spawn } from "child_process"; |
||||||
|
const profile: Profile = { |
||||||
|
name: 'hardhat', |
||||||
|
displayName: 'electron slither', |
||||||
|
description: 'electron slither', |
||||||
|
} |
||||||
|
|
||||||
|
export class HardhatPlugin extends ElectronBasePlugin { |
||||||
|
clients: any[] |
||||||
|
constructor() { |
||||||
|
super(profile, clientProfile, HardhatPluginClient) |
||||||
|
this.methods = [...super.methods] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const clientProfile: Profile = { |
||||||
|
name: 'hardhat', |
||||||
|
displayName: 'electron hardhat', |
||||||
|
description: 'electron hardhat', |
||||||
|
methods: ['sync', 'compile'] |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
class HardhatPluginClient extends ElectronBasePluginRemixdClient { |
||||||
|
watcher: chokidar.FSWatcher |
||||||
|
warnlog: boolean |
||||||
|
buildPath: string |
||||||
|
cachePath: string |
||||||
|
logTimeout: NodeJS.Timeout |
||||||
|
processingTimeout: NodeJS.Timeout |
||||||
|
|
||||||
|
async onActivation(): Promise<void> { |
||||||
|
console.log('Hardhat plugin activated') |
||||||
|
this.call('terminal', 'log', { type: 'log', value: 'Hardhat plugin activated' }) |
||||||
|
|
||||||
|
this.on('fs' as any, 'workingDirChanged', async (path: string) => { |
||||||
|
console.log('workingDirChanged hardhat', path) |
||||||
|
this.currentSharedFolder = path |
||||||
|
this.startListening() |
||||||
|
}) |
||||||
|
this.currentSharedFolder = await this.call('fs' as any, 'getWorkingDir') |
||||||
|
if(this.currentSharedFolder) this.startListening() |
||||||
|
} |
||||||
|
|
||||||
|
startListening() { |
||||||
|
this.buildPath = utils.absolutePath('artifacts/contracts', this.currentSharedFolder) |
||||||
|
if (fs.existsSync(this.buildPath)) { |
||||||
|
this.listenOnHardhatCompilation() |
||||||
|
} else { |
||||||
|
console.log('If you are using Hardhat, run `npx hardhat compile` or run the compilation with `Enable Hardhat Compilation` checked from the Remix IDE.') |
||||||
|
this.listenOnHardHatFolder() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
compile(configPath: string) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const cmd = `npx hardhat compile --config ${utils.normalizePath(configPath)}` |
||||||
|
const options = { cwd: this.currentSharedFolder, shell: true } |
||||||
|
const child = spawn(cmd, options) |
||||||
|
let result = '' |
||||||
|
let error = '' |
||||||
|
child.stdout.on('data', (data) => { |
||||||
|
const msg = `[Hardhat Compilation]: ${data.toString()}` |
||||||
|
console.log('\x1b[32m%s\x1b[0m', msg) |
||||||
|
result += msg + '\n' |
||||||
|
}) |
||||||
|
child.stderr.on('data', (err) => { |
||||||
|
error += `[Hardhat Compilation]: ${err.toString()} \n` |
||||||
|
}) |
||||||
|
child.on('close', () => { |
||||||
|
if (error && result) resolve(error + result) |
||||||
|
else if (error) reject(error) |
||||||
|
else resolve(result) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
checkPath() { |
||||||
|
if (!fs.existsSync(this.buildPath)) { |
||||||
|
this.listenOnHardHatFolder() |
||||||
|
return false |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
private async processArtifact() { |
||||||
|
console.log('processing artifact') |
||||||
|
if (!this.checkPath()) return |
||||||
|
// resolving the files
|
||||||
|
const folderFiles = await fs.promises.readdir(this.buildPath) |
||||||
|
const targetsSynced = [] |
||||||
|
// name of folders are file names
|
||||||
|
for (const file of folderFiles) { // ["artifacts/contracts/Greeter.sol/"]
|
||||||
|
const contractFilePath = join(this.buildPath, file) |
||||||
|
const stat = await fs.promises.stat(contractFilePath) |
||||||
|
if (!stat.isDirectory()) continue |
||||||
|
const files = await fs.promises.readdir(contractFilePath) |
||||||
|
const compilationResult = { |
||||||
|
input: {}, |
||||||
|
output: { |
||||||
|
contracts: {}, |
||||||
|
sources: {} |
||||||
|
}, |
||||||
|
solcVersion: null, |
||||||
|
target: null |
||||||
|
} |
||||||
|
for (const file of files) { |
||||||
|
if (file.endsWith('.dbg.json')) { // "artifacts/contracts/Greeter.sol/Greeter.dbg.json"
|
||||||
|
const stdFile = file.replace('.dbg.json', '.json') |
||||||
|
const contentStd = await fs.promises.readFile(join(contractFilePath, stdFile), { encoding: 'utf-8' }) |
||||||
|
const contentDbg = await fs.promises.readFile(join(contractFilePath, file), { encoding: 'utf-8' }) |
||||||
|
const jsonDbg = JSON.parse(contentDbg) |
||||||
|
const jsonStd = JSON.parse(contentStd) |
||||||
|
compilationResult.target = jsonStd.sourceName |
||||||
|
|
||||||
|
targetsSynced.push(compilationResult.target) |
||||||
|
const path = join(contractFilePath, jsonDbg.buildInfo) |
||||||
|
const content = await fs.promises.readFile(path, { encoding: 'utf-8' }) |
||||||
|
|
||||||
|
await this.feedContractArtifactFile(content, compilationResult) |
||||||
|
} |
||||||
|
if (compilationResult.target) { |
||||||
|
// we are only interested in the contracts that are in the target of the compilation
|
||||||
|
compilationResult.output = { |
||||||
|
...compilationResult.output, |
||||||
|
contracts: { [compilationResult.target]: compilationResult.output.contracts[compilationResult.target] } |
||||||
|
} |
||||||
|
this.emit('compilationFinished', compilationResult.target, { sources: compilationResult.input }, 'soljson', compilationResult.output, compilationResult.solcVersion) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
clearTimeout(this.logTimeout) |
||||||
|
this.logTimeout = setTimeout(() => { |
||||||
|
this.call('terminal', 'log', { value: 'receiving compilation result from Hardhat. Select a file to populate the contract interaction interface.', type: 'log' }) |
||||||
|
if (targetsSynced.length) { |
||||||
|
console.log(`Processing artifacts for files: ${[...new Set(targetsSynced)].join(', ')}`) |
||||||
|
// @ts-ignore
|
||||||
|
this.call('terminal', 'log', { type: 'log', value: `synced with Hardhat: ${[...new Set(targetsSynced)].join(', ')}` }) |
||||||
|
} else { |
||||||
|
console.log('No artifacts to process') |
||||||
|
// @ts-ignore
|
||||||
|
this.call('terminal', 'log', { type: 'log', value: 'No artifacts from Hardhat to process' }) |
||||||
|
} |
||||||
|
}, 1000) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
listenOnHardHatFolder() { |
||||||
|
console.log('Hardhat artifacts folder doesn\'t exist... waiting for the compilation.') |
||||||
|
try { |
||||||
|
if (this.watcher) this.watcher.close() |
||||||
|
this.watcher = chokidar.watch(this.currentSharedFolder, { depth: 2, ignorePermissionErrors: true, ignoreInitial: true }) |
||||||
|
// watch for new folders
|
||||||
|
this.watcher.on('addDir', (path: string) => { |
||||||
|
console.log('add dir hardhat', path) |
||||||
|
if (fs.existsSync(this.buildPath)) { |
||||||
|
this.listenOnHardhatCompilation() |
||||||
|
} |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log('listenOnHardHatFolder', e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async triggerProcessArtifact() { |
||||||
|
console.log('triggerProcessArtifact') |
||||||
|
// prevent multiple calls
|
||||||
|
clearTimeout(this.processingTimeout) |
||||||
|
this.processingTimeout = setTimeout(async () => await this.processArtifact(), 1000) |
||||||
|
} |
||||||
|
|
||||||
|
listenOnHardhatCompilation() { |
||||||
|
try { |
||||||
|
console.log('listening on Hardhat compilation...', this.buildPath) |
||||||
|
if (this.watcher) this.watcher.close() |
||||||
|
this.watcher = chokidar.watch(this.buildPath, { depth: 1, ignorePermissionErrors: true, ignoreInitial: true }) |
||||||
|
this.watcher.on('change', async () => await this.triggerProcessArtifact()) |
||||||
|
this.watcher.on('add', async () => await this.triggerProcessArtifact()) |
||||||
|
this.watcher.on('unlink', async () => await this.triggerProcessArtifact()) |
||||||
|
// process the artifact on activation
|
||||||
|
this.processArtifact() |
||||||
|
} catch (e) { |
||||||
|
console.log('listenOnHardhatCompilation', e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async sync() { |
||||||
|
console.log('syncing from Hardhat') |
||||||
|
this.processArtifact() |
||||||
|
} |
||||||
|
|
||||||
|
async feedContractArtifactFile(artifactContent, compilationResultPart) { |
||||||
|
const contentJSON = JSON.parse(artifactContent) |
||||||
|
compilationResultPart.solcVersion = contentJSON.solcVersion |
||||||
|
for (const file in contentJSON.input.sources) { |
||||||
|
const source = contentJSON.input.sources[file] |
||||||
|
const absPath = join(this.currentSharedFolder, file) |
||||||
|
if (fs.existsSync(absPath)) { // if not that is a lib
|
||||||
|
const contentOnDisk = await fs.promises.readFile(absPath, { encoding: 'utf-8' }) |
||||||
|
if (contentOnDisk === source.content) { |
||||||
|
compilationResultPart.input[file] = source |
||||||
|
compilationResultPart.output['sources'][file] = contentJSON.output.sources[file] |
||||||
|
compilationResultPart.output['contracts'][file] = contentJSON.output.contracts[file] |
||||||
|
if (contentJSON.output.errors && contentJSON.output.errors.length) { |
||||||
|
compilationResultPart.output['errors'] = contentJSON.output.errors.filter(error => error.sourceLocation.file === file) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,197 @@ |
|||||||
|
import { Profile } from "@remixproject/plugin-utils"; |
||||||
|
import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" |
||||||
|
|
||||||
|
import { ElectronBasePluginRemixdClient } from "../lib/remixd" |
||||||
|
import * as utils from '../lib/utils' |
||||||
|
import { existsSync, readdirSync, readFileSync, unlinkSync } from "fs-extra"; |
||||||
|
|
||||||
|
export interface OutputStandard { |
||||||
|
description: string |
||||||
|
title: string |
||||||
|
confidence: string |
||||||
|
severity: string |
||||||
|
sourceMap: any |
||||||
|
category?: string |
||||||
|
reference?: string |
||||||
|
example?: any |
||||||
|
[key: string]: any |
||||||
|
} |
||||||
|
|
||||||
|
const { spawn, execSync } = require('child_process') // eslint-disable-line
|
||||||
|
const profile: Profile = { |
||||||
|
name: 'slither', |
||||||
|
displayName: 'electron slither', |
||||||
|
description: 'electron slither', |
||||||
|
} |
||||||
|
|
||||||
|
export class SlitherPlugin extends ElectronBasePlugin { |
||||||
|
clients: any[] |
||||||
|
constructor() { |
||||||
|
super(profile, clientProfile, SlitherPluginClient) |
||||||
|
this.methods = [...super.methods] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const clientProfile: Profile = { |
||||||
|
name: 'slither', |
||||||
|
displayName: 'electron slither', |
||||||
|
description: 'electron slither', |
||||||
|
methods: ['analyse'] |
||||||
|
} |
||||||
|
|
||||||
|
class SlitherPluginClient extends ElectronBasePluginRemixdClient { |
||||||
|
|
||||||
|
mapNpmDepsDir(list) { |
||||||
|
const remixNpmDepsPath = utils.absolutePath('.deps/npm', this.currentSharedFolder) |
||||||
|
const localNpmDepsPath = utils.absolutePath('node_modules', this.currentSharedFolder) |
||||||
|
const npmDepsExists = existsSync(remixNpmDepsPath) |
||||||
|
const nodeModulesExists = existsSync(localNpmDepsPath) |
||||||
|
let isLocalDep = false |
||||||
|
let isRemixDep = false |
||||||
|
let allowPathString = '' |
||||||
|
let remapString = '' |
||||||
|
|
||||||
|
for (const e of list) { |
||||||
|
const importPath = e.replace(/import ['"]/g, '').trim() |
||||||
|
const packageName = importPath.split('/')[0] |
||||||
|
if (nodeModulesExists && readdirSync(localNpmDepsPath).includes(packageName)) { |
||||||
|
isLocalDep = true |
||||||
|
remapString += `${packageName}=./node_modules/${packageName} ` |
||||||
|
} else if (npmDepsExists && readdirSync(remixNpmDepsPath).includes(packageName)) { |
||||||
|
isRemixDep = true |
||||||
|
remapString += `${packageName}=./.deps/npm/${packageName} ` |
||||||
|
} |
||||||
|
} |
||||||
|
if (isLocalDep) allowPathString += './node_modules,' |
||||||
|
if (isRemixDep) allowPathString += './.deps/npm,' |
||||||
|
|
||||||
|
return { remapString, allowPathString } |
||||||
|
} |
||||||
|
|
||||||
|
transform(detectors: Record<string, any>[]): OutputStandard[] { |
||||||
|
const standardReport: OutputStandard[] = [] |
||||||
|
for (const e of detectors) { |
||||||
|
const obj = {} as OutputStandard |
||||||
|
obj.description = e.description |
||||||
|
obj.title = e.check |
||||||
|
obj.confidence = e.confidence |
||||||
|
obj.severity = e.impact |
||||||
|
obj.sourceMap = e.elements.map((element) => { |
||||||
|
delete element.source_mapping.filename_used |
||||||
|
delete element.source_mapping.filename_absolute |
||||||
|
return element |
||||||
|
}) |
||||||
|
standardReport.push(obj) |
||||||
|
} |
||||||
|
return standardReport |
||||||
|
} |
||||||
|
|
||||||
|
analyse(filePath: string, compilerConfig: Record<string, any>) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const options = { cwd: this.currentSharedFolder, shell: true } |
||||||
|
|
||||||
|
const { currentVersion, optimize, evmVersion } = compilerConfig |
||||||
|
if (currentVersion && currentVersion.includes('+commit')) { |
||||||
|
// Get compiler version with commit id e.g: 0.8.2+commit.661d110
|
||||||
|
const versionString: string = currentVersion.substring(0, currentVersion.indexOf('+commit') + 16) |
||||||
|
this.log(`[Slither Analysis]: Compiler version is ${versionString}`) |
||||||
|
let solcOutput: Buffer |
||||||
|
// Check solc current installed version
|
||||||
|
try { |
||||||
|
solcOutput = execSync('solc --version', options) |
||||||
|
} catch (err) { |
||||||
|
this.error(err) |
||||||
|
reject(new Error('Error in running solc command')) |
||||||
|
} |
||||||
|
if (!solcOutput.toString().includes(versionString)) { |
||||||
|
this.log('[Slither Analysis]: Compiler version is different from installed solc version') |
||||||
|
// Get compiler version without commit id e.g: 0.8.2
|
||||||
|
const version: string = versionString.substring(0, versionString.indexOf('+commit')) |
||||||
|
// List solc versions installed using solc-select
|
||||||
|
try { |
||||||
|
const solcSelectInstalledVersions: Buffer = execSync('solc-select versions', options) |
||||||
|
// Check if required version is already installed
|
||||||
|
if (!solcSelectInstalledVersions.toString().includes(version)) { |
||||||
|
this.log(`[Slither Analysis]: Installing ${version} using solc-select`) |
||||||
|
// Install required version
|
||||||
|
execSync(`solc-select install ${version}`, options) |
||||||
|
} |
||||||
|
this.log(`[Slither Analysis]: Setting ${version} as current solc version using solc-select`) |
||||||
|
// Set solc current version as required version
|
||||||
|
execSync(`solc-select use ${version}`, options) |
||||||
|
} catch (err) { |
||||||
|
this.error(err) |
||||||
|
reject(new Error('Error in running solc-select command')) |
||||||
|
} |
||||||
|
} else this.log('[Slither Analysis]: Compiler version is same as installed solc version') |
||||||
|
} |
||||||
|
// Allow paths and set solc remapping for import URLs
|
||||||
|
const fileContent = readFileSync(utils.absolutePath(filePath, this.currentSharedFolder), 'utf8') |
||||||
|
const importsArr = fileContent.match(/import ['"][^.|..](.+?)['"];/g) |
||||||
|
let remaps = '' |
||||||
|
if (importsArr?.length) { |
||||||
|
const { remapString } = this.mapNpmDepsDir(importsArr) |
||||||
|
remaps = remapString.trim() |
||||||
|
} |
||||||
|
const optimizeOption: string = optimize ? '--optimize' : '' |
||||||
|
const evmOption: string = evmVersion ? `--evm-version ${evmVersion}` : '' |
||||||
|
let solcArgs = '' |
||||||
|
if (optimizeOption) { |
||||||
|
solcArgs += optimizeOption + ' ' |
||||||
|
} |
||||||
|
if (evmOption) { |
||||||
|
if (!solcArgs.endsWith(' ')) solcArgs += ' ' |
||||||
|
solcArgs += evmOption |
||||||
|
} |
||||||
|
if (solcArgs) { |
||||||
|
solcArgs = `--solc-args "${solcArgs.trimStart()}"` |
||||||
|
} |
||||||
|
const solcRemaps = remaps ? `--solc-remaps "${remaps}"` : '' |
||||||
|
|
||||||
|
const outputFile = 'remix-slither-report.json' |
||||||
|
try { |
||||||
|
// We don't keep the previous analysis
|
||||||
|
const outputFilePath = utils.absolutePath(outputFile, this.currentSharedFolder) |
||||||
|
if (existsSync(outputFilePath)) unlinkSync(outputFilePath) |
||||||
|
} catch (e) { |
||||||
|
this.error('unable to remove the output file') |
||||||
|
this.error(e.message) |
||||||
|
} |
||||||
|
const cmd = `slither ${filePath} ${solcArgs} ${solcRemaps} --json ${outputFile}` |
||||||
|
this.log('[Slither Analysis]: Running Slither...') |
||||||
|
// Added `stdio: 'ignore'` as for contract with NPM imports analysis which is exported in 'stderr'
|
||||||
|
// get too big and hangs the process. We process analysis from the report file only
|
||||||
|
const child = spawn(cmd, { cwd: this.currentSharedFolder, shell: true, stdio: 'ignore' }) |
||||||
|
|
||||||
|
const response = {} |
||||||
|
child.on('close', () => { |
||||||
|
const outputFileAbsPath: string = utils.absolutePath(outputFile, this.currentSharedFolder) |
||||||
|
// Check if slither report file exists
|
||||||
|
if (existsSync(outputFileAbsPath)) { |
||||||
|
let report = readFileSync(outputFileAbsPath, 'utf8') |
||||||
|
report = JSON.parse(report) |
||||||
|
if (report['success']) { |
||||||
|
response['status'] = true |
||||||
|
if (!report['results'] || !report['results'].detectors || !report['results'].detectors.length) { |
||||||
|
response['count'] = 0 |
||||||
|
} else { |
||||||
|
const { detectors } = report['results'] |
||||||
|
response['count'] = detectors.length |
||||||
|
response['data'] = this.transform(detectors) |
||||||
|
} |
||||||
|
|
||||||
|
resolve(response) |
||||||
|
} else { |
||||||
|
this.log(report['error']) |
||||||
|
reject(new Error('Error in running Slither Analysis.')) |
||||||
|
} |
||||||
|
} else { |
||||||
|
this.error('Error in generating Slither Analysis Report. Make sure Slither is properly installed.') |
||||||
|
reject(new Error('Error in generating Slither Analysis Report. Make sure Slither is properly installed.')) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -1,9 +0,0 @@ |
|||||||
export type branch = { |
|
||||||
name: string |
|
||||||
remote: remote |
|
||||||
} |
|
||||||
|
|
||||||
export type remote = { |
|
||||||
name: string |
|
||||||
url: string |
|
||||||
} |
|
@ -0,0 +1,51 @@ |
|||||||
|
import { screen } from 'electron'; |
||||||
|
import { isPackaged, isE2E } from "../main"; |
||||||
|
|
||||||
|
|
||||||
|
var MatomoTracker = require('matomo-tracker'); |
||||||
|
|
||||||
|
// Function to send events to Matomo
|
||||||
|
export function trackEvent(category: string, action: string, name: string, value: string | number, new_visit: number = 0): void { |
||||||
|
var matomo = new MatomoTracker(35, 'http://ethereumfoundation.matomo.cloud/matomo.php'); |
||||||
|
matomo.on('error', function (err: any) { |
||||||
|
console.log('error tracking request: ', err); |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
// Customize the user agent
|
||||||
|
const electronVersion = process.versions.electron; |
||||||
|
const chromiumVersion = process.versions.chrome; |
||||||
|
const os = process.platform; // 'darwin', 'win32', 'linux', etc.
|
||||||
|
const osVersion = process.getSystemVersion(); |
||||||
|
|
||||||
|
const ua = `Electron/${electronVersion} (Chromium/${chromiumVersion}) ${os} ${osVersion}`; |
||||||
|
|
||||||
|
|
||||||
|
const res = `${screen.getPrimaryDisplay().size.width}x${screen.getPrimaryDisplay().size.height}`; |
||||||
|
|
||||||
|
if ((process.env.NODE_ENV === 'production' || isPackaged) && !isE2E) { |
||||||
|
console.log('trackEvent', category, action, name, value, ua, new_visit); |
||||||
|
matomo.track({ |
||||||
|
e_c: category, |
||||||
|
e_a: action, |
||||||
|
e_n: name, |
||||||
|
e_v: value, |
||||||
|
ua, |
||||||
|
new_visit, |
||||||
|
res, |
||||||
|
url: 'https://github.com/remix-project-org/remix-desktop' |
||||||
|
// You can add other parameters if needed
|
||||||
|
}, (error: any) => { |
||||||
|
if (error) { |
||||||
|
console.error('Error tracking event:', error); |
||||||
|
} else { |
||||||
|
console.log('Event tracked successfully'); |
||||||
|
} |
||||||
|
}); |
||||||
|
} else { |
||||||
|
console.log('Matomo tracking is disabled'); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,2 @@ |
|||||||
|
{"openedFolders":["/home/bunsen/Documents/remix-reward"], |
||||||
|
"recentFolders":["/home/bunsen/Documents/remix-reward"]} |
@ -0,0 +1,195 @@ |
|||||||
|
import { spawn, ChildProcess } from "child_process" |
||||||
|
|
||||||
|
export async function getBranches(path: string): Promise<string> { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn('git', ['branch'], { cwd: path }) |
||||||
|
let branches = '' |
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
console.log('stdout git branches', data.toString()) |
||||||
|
branches += data.toString() |
||||||
|
}) |
||||||
|
git.stderr.on('data', function (data) { |
||||||
|
console.log('stderr git branches', data.toString()) |
||||||
|
reject(data.toString()) |
||||||
|
}) |
||||||
|
git.on('close', function () { |
||||||
|
resolve(branches) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
export async function getGitLog(path: string): Promise<string> { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn('git', ['log'], { cwd: path }) |
||||||
|
let logs = '' |
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
logs += data.toString() |
||||||
|
}) |
||||||
|
git.stderr.on('err', function (data) { |
||||||
|
reject(data.toString()) |
||||||
|
}) |
||||||
|
git.on('close', function () { |
||||||
|
resolve(logs) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
export async function cloneOnServer(repo: string, path: string, name: string = 'bare') { |
||||||
|
console.log('cloning', repo, path) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn(`rm -rf ${name} && git`, ['clone', repo], { cwd: path, shell: true, detached: true }); |
||||||
|
|
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
console.log('stdout data cloning', data.toString()); |
||||||
|
if (data.toString().includes('done')) { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.stderr.on('data', function (data) { |
||||||
|
console.log('stderr data cloning', data.toString()); |
||||||
|
if (data.toString().includes('into')) { |
||||||
|
setTimeout(() => { |
||||||
|
resolve(git); |
||||||
|
}, 5000) |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('error', (error) => { |
||||||
|
reject(`Process error: ${error.message}`); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('exit', (code, signal) => { |
||||||
|
if (code !== 0) { |
||||||
|
reject(`Process exited with code: ${code} and signal: ${signal}`); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export async function onLocalGitRepoAddFile(path: string, file: string) { |
||||||
|
console.log('adding file', file) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn('touch', [file], { cwd: path }); |
||||||
|
|
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
console.log('stdout data adding file', data.toString()); |
||||||
|
if (data.toString().includes('done')) { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.stderr.on('data', function (data) { |
||||||
|
console.error('stderr adding file', data.toString()); |
||||||
|
reject(data.toString()); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('error', (error) => { |
||||||
|
reject(`Process error: ${error.message}`); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('exit', (code, signal) => { |
||||||
|
if (code !== 0) { |
||||||
|
reject(`Process exited with code: ${code} and signal: ${signal}`); |
||||||
|
} else { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export async function onLocalGitRepoPush(path: string, branch: string = 'master') { |
||||||
|
console.log('pushing', path) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn('git', ['push', 'origin', branch], { cwd: path, shell: true, detached: true }); |
||||||
|
|
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
console.log('stdout data pushing', data.toString()); |
||||||
|
if (data.toString().includes('done')) { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.stderr.on('data', function (data) { |
||||||
|
console.error('stderr data pushing', data.toString()); |
||||||
|
if (data.toString().includes(branch)) { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('error', (error) => { |
||||||
|
reject(`Process error: ${error.message}`); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('exit', (code, signal) => { |
||||||
|
if (code !== 0) { |
||||||
|
reject(`Process exited with code: ${code} and signal: ${signal}`); |
||||||
|
} else { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
export async function createCommitOnLocalServer(path: string, message: string) { |
||||||
|
console.log('committing', message, path) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
const git = spawn('git add . && git', ['commit', '-m', message], { cwd: path, shell: true, detached: true }); |
||||||
|
|
||||||
|
git.stdout.on('data', function (data) { |
||||||
|
console.log('data stdout committing', data.toString()); |
||||||
|
if (data.toString().includes(message)) { |
||||||
|
setTimeout(() => { |
||||||
|
resolve(git); |
||||||
|
}, 1000) |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
git.stderr.on('data', function (data) { |
||||||
|
console.error('data commiting', data.toString()); |
||||||
|
reject(data.toString()); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('error', (error) => { |
||||||
|
console.error('error', error); |
||||||
|
reject(`Process error: ${error.message}`); |
||||||
|
}); |
||||||
|
|
||||||
|
git.on('exit', (code, signal) => { |
||||||
|
if (code !== 0) { |
||||||
|
console.error('exit', code, signal); |
||||||
|
reject(`Process exited with code: ${code} and signal: ${signal}`); |
||||||
|
} else { |
||||||
|
resolve(git); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
export async function spawnGitServer(path: string): Promise<ChildProcess> { |
||||||
|
console.log(process.cwd()) |
||||||
|
try { |
||||||
|
const server = spawn('yarn && sh setup.sh && yarn start:server', [`${path}`], { cwd: process.cwd() + '/../remix-ide-e2e/src/githttpbackend/', shell: true, detached: true }) |
||||||
|
console.log('spawned', server.stdout.closed, server.stderr.closed) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.stdout.on('data', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
if ( |
||||||
|
data.toString().includes('is listening') |
||||||
|
|| data.toString().includes('address already in use') |
||||||
|
) { |
||||||
|
console.log('resolving') |
||||||
|
resolve(server) |
||||||
|
} |
||||||
|
}) |
||||||
|
server.stderr.on('err', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
reject(data.toString()) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
import os from 'os'; |
||||||
|
import fs from 'fs'; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const useIsoGit = process.argv.includes('--use-isogit'); |
||||||
|
const useOffline = process.argv.includes('--use-offline'); |
||||||
|
|
||||||
|
// Function to read JSON file synchronously
|
||||||
|
function readJSONFileSync(filename: string): any { |
||||||
|
try { |
||||||
|
const data = fs.readFileSync(filename, 'utf8'); |
||||||
|
return JSON.parse(data); |
||||||
|
} catch (err) { |
||||||
|
throw err; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const packageData: any = readJSONFileSync('package.json'); |
||||||
|
const version = packageData.version; |
||||||
|
|
||||||
|
let channel: string = '' |
||||||
|
|
||||||
|
if (version.includes('beta')) { |
||||||
|
channel = 'Beta'; |
||||||
|
} else if (version.includes('alpha')) { |
||||||
|
channel = 'Alpha'; |
||||||
|
} else if (version.includes('insiders')) { |
||||||
|
channel = 'Insiders'; |
||||||
|
} |
||||||
|
|
||||||
|
// Determine if running on CircleCI or locally with --e2e-local
|
||||||
|
const isLocalE2E = process.argv.includes('--e2e-local') && !process.env.CIRCLECI; |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
src_folders: ['build-e2e/remixdesktop/test/tests/app'], |
||||||
|
output_folder: './reports/tests', |
||||||
|
custom_commands_path: ['build-e2e/remix-ide-e2e/src/commands'], |
||||||
|
page_objects_path: '', |
||||||
|
globals_path: '', |
||||||
|
test_settings: { |
||||||
|
default: { |
||||||
|
enable_fail_fast: true, |
||||||
|
selenium_port: 4444, |
||||||
|
selenium_host: 'localhost', |
||||||
|
globals: { |
||||||
|
waitForConditionTimeout: 10000, |
||||||
|
asyncHookTimeout: 100000 |
||||||
|
}, |
||||||
|
screenshots: { |
||||||
|
enabled: true, |
||||||
|
path: './reports/screenshots', |
||||||
|
on_failure: true, |
||||||
|
on_error: true |
||||||
|
}, |
||||||
|
webdriver: { |
||||||
|
start_process: true, |
||||||
|
timeout_options: { |
||||||
|
timeout: 60000, |
||||||
|
retry_attempts: 3 |
||||||
|
} |
||||||
|
}, |
||||||
|
desiredCapabilities: { |
||||||
|
browserName: 'chrome', |
||||||
|
javascriptEnabled: true, |
||||||
|
acceptSslCerts: true, |
||||||
|
'goog:chromeOptions': (() => { |
||||||
|
const type = os.type(); |
||||||
|
const arch = os.arch(); |
||||||
|
let binaryPath = ""; |
||||||
|
// Check if running on CircleCI or locally
|
||||||
|
let args = process.env.CIRCLECI ? ["--e2e"] : ["--e2e-local"]; |
||||||
|
|
||||||
|
if(useIsoGit) args = [...args, '--use-isogit']; |
||||||
|
if(useOffline) args = [...args, '--use-offline']; |
||||||
|
|
||||||
|
// Set display size
|
||||||
|
const windowSize = "--window-size=1000,1000"; |
||||||
|
args = [...args]; |
||||||
|
|
||||||
|
switch (type) { |
||||||
|
case 'Windows_NT': |
||||||
|
binaryPath = `./release/win-unpacked/Remix-Desktop-${channel}.exe`; |
||||||
|
break; |
||||||
|
case 'Darwin': |
||||||
|
binaryPath = arch === 'x64' ?
|
||||||
|
`release/mac/Remix-Desktop-${channel}.app/Contents/MacOS/Remix-Desktop-${channel}` : |
||||||
|
`release/mac-arm64/Remix-Desktop-${channel}.app/Contents/MacOS/Remix-Desktop-${channel}`; |
||||||
|
break; |
||||||
|
case 'Linux': |
||||||
|
binaryPath = "release/linux-unpacked/remixdesktop"; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
console.log('binaryPath', binaryPath); |
||||||
|
return { |
||||||
|
binary: binaryPath, |
||||||
|
args: args |
||||||
|
}; |
||||||
|
})() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,37 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
'download compiler': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.pause(1000) |
||||||
|
.setSolidityCompilerVersion('soljson-v0.8.23+commit.f704f362.js') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-id='selectedVersion' and contains(.,'0.8.23+commit.f704f362')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Compiler downloaded from https://binaries.soliditylang.org/wasm/soljson-v0.8.23+commit.f704f362.js to soljson-v0.8.23+commit.f704f362.js', 10000) |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: |
||||||
|
"//a[@data-id='dropdown-item-soljson-v0.8.23+commit.f704f362.js']//*[contains(@class, 'fa-arrow-circle-down')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'refresh': function (browser: NightwatchBrowser) { |
||||||
|
browser.refresh() |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.waitForElementVisible('*[data-id="versionSelector"]') |
||||||
|
.click('*[data-id="versionSelector"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: |
||||||
|
"//a[@data-id='dropdown-item-soljson-v0.8.23+commit.f704f362.js']//*[contains(@class, 'fa-arrow-circle-down')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,122 @@ |
|||||||
|
import {NightwatchBrowser} from 'nightwatch' |
||||||
|
|
||||||
|
const testsBash = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
open: function (browser: NightwatchBrowser) { |
||||||
|
browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') |
||||||
|
}, |
||||||
|
'open xterm linux and create a file': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="tabXTerm"]', 10000) |
||||||
|
.click('*[data-id="tabXTerm"]') |
||||||
|
.waitForElementVisible('*[data-type="remixUIXT"]', 10000) |
||||||
|
.click('*[data-type="remixUIXT"]') |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('mkdir dir && cd dir && echo "test" >> example.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemdir"]', 10000) |
||||||
|
.openFile('dir') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemdir/example.txt"]', 10000) |
||||||
|
.openFile('dir/example.txt') |
||||||
|
.getEditorValue((result) => { |
||||||
|
browser.assert.equal(result, 'test\n') |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-type="remixUIXT"]', 10000) |
||||||
|
.click('*[data-type="remixUIXT"]') |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('echo "123" >> example.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.getEditorValue((result) => { |
||||||
|
browser.assert.equal(result, 'test\n123\n') |
||||||
|
}) |
||||||
|
.setEditorValue('somethinginthere') |
||||||
|
.pause(1000) |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('cat example.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok((result.value as string).includes('somethinginthere')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
const testsWindows = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
open: function (browser: NightwatchBrowser) { |
||||||
|
browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') |
||||||
|
}, |
||||||
|
'open xterm window and create a file': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="tabXTerm"]', 10000) |
||||||
|
.click('*[data-id="tabXTerm"]') |
||||||
|
.waitForElementVisible('*[data-id="select_shell"]') |
||||||
|
.click('*[data-id="select_shell"]') |
||||||
|
.waitForElementVisible('*[data-id="select_powershell.exe"]') |
||||||
|
.click('*[data-id="select_powershell.exe"]') |
||||||
|
.pause(3000) |
||||||
|
.waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) |
||||||
|
.click("[data-active='1'][data-type='remixUIXT']") |
||||||
|
.pause(1000) |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('New-Item -ItemType Directory -Name "dir" ; Set-Location -Path "./dir" ; Add-Content -Path "example.txt" -Value "test" -Encoding UTF8').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemdir"]', 10000) |
||||||
|
.openFile('dir') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemdir/example.txt"]', 10000) |
||||||
|
.openFile('dir/example.txt').pause(1000) |
||||||
|
.getEditorValue((result) => { |
||||||
|
browser.assert.equal(result, 'test\r\n') |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) |
||||||
|
.click("[data-active='1'][data-type='remixUIXT']") |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('Add-Content -Path "example.txt" -Value "123" -Encoding UTF8').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.getEditorValue((result) => { |
||||||
|
browser.assert.equal(result, 'test\r\n123\r\n') |
||||||
|
}) |
||||||
|
.setEditorValue('somethinginthere') |
||||||
|
.pause(1000) |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('Get-Content example.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}).pause(1000) |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok((result.value as string).includes('somethinginthere')) |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
...process.platform.startsWith('win')?testsWindows:testsBash |
||||||
|
} |
@ -0,0 +1,157 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
import { ChildProcess, spawn, execSync } from 'child_process' |
||||||
|
import { homedir } from 'os' |
||||||
|
import path from 'path' |
||||||
|
import os from 'os' |
||||||
|
|
||||||
|
const projectDir = path.join('remix-desktop-test-' + Date.now().toString()) |
||||||
|
const dir = '/tmp/' + projectDir |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
installFoundry: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
await downloadFoundry() |
||||||
|
await installFoundry() |
||||||
|
await initFoundryProject() |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
addScript: function (browser: NightwatchBrowser) { |
||||||
|
// run script in console
|
||||||
|
browser.executeAsync(function (dir, done) { |
||||||
|
(window as any).electronAPI.openFolderInSameWindow(dir + '/hello_foundry/').then(done) |
||||||
|
}, [dir], () => { |
||||||
|
console.log('done window opened') |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewDivDraggableItemfoundry.toml"]', 10000) |
||||||
|
}, |
||||||
|
compile: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
console.log('generating compilation result') |
||||||
|
await buildFoundryProject() |
||||||
|
done() |
||||||
|
}) |
||||||
|
.expect.element('*[data-id="terminalJournal"]').text.to.contain('receiving compilation result from Foundry').before(60000) |
||||||
|
|
||||||
|
let contractAaddress |
||||||
|
browser.clickLaunchIcon('filePanel') |
||||||
|
.openFile('src') |
||||||
|
.openFile('src/Counter.sol') |
||||||
|
.clickLaunchIcon('udapp') |
||||||
|
.selectContract('Counter') |
||||||
|
.createContract('') |
||||||
|
.getAddressAtPosition(0, (address) => { |
||||||
|
console.log(contractAaddress) |
||||||
|
contractAaddress = address |
||||||
|
}) |
||||||
|
.clickInstance(0) |
||||||
|
.clickFunction('increment - transact (not payable)') |
||||||
|
.perform((done) => { |
||||||
|
browser.testConstantFunction(contractAaddress, 'number - call', null, '0:\nuint256: 1').perform(() => { |
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
async function downloadFoundry(): Promise<void> { |
||||||
|
console.log('downloadFoundry', process.cwd()) |
||||||
|
try { |
||||||
|
const server = spawn('curl -L https://foundry.paradigm.xyz | bash', [], { cwd: process.cwd(), shell: true, detached: true }) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.stdout.on('data', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
if ( |
||||||
|
data.toString().includes("simply run 'foundryup' to install Foundry") |
||||||
|
|| data.toString().includes("foundryup: could not detect shell, manually add") |
||||||
|
) { |
||||||
|
console.log('resolving') |
||||||
|
resolve() |
||||||
|
} |
||||||
|
}) |
||||||
|
server.stderr.on('err', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
reject(data.toString()) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function installFoundry(): Promise<void> { |
||||||
|
console.log('installFoundry', process.cwd()) |
||||||
|
try { |
||||||
|
const server = spawn('export PATH="' + homedir() + '/.foundry/bin:$PATH" && foundryup', [], { cwd: process.cwd(), shell: true, detached: true }) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.stdout.on('data', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
if ( |
||||||
|
data.toString().includes("foundryup: done!") |
||||||
|
) { |
||||||
|
console.log('resolving') |
||||||
|
resolve() |
||||||
|
} |
||||||
|
}) |
||||||
|
server.stderr.on('err', function (data) { |
||||||
|
console.log(data.toString()) |
||||||
|
reject(data.toString()) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function initFoundryProject(): Promise<void> { |
||||||
|
console.log('initFoundryProject', homedir()) |
||||||
|
try { |
||||||
|
if (process.env.CIRCLECI) { |
||||||
|
spawn('git config --global user.email \"you@example.com\"', [], { cwd: homedir(), shell: true, detached: true }) |
||||||
|
spawn('git config --global user.name \"Your Name\"', [], { cwd: homedir(), shell: true, detached: true }) |
||||||
|
} |
||||||
|
spawn('mkdir ' + projectDir, [], { cwd: '/tmp/', shell: true, detached: true }) |
||||||
|
const server = spawn('export PATH="' + homedir() + '/.foundry/bin:$PATH" && forge init hello_foundry', [], { cwd: dir, shell: true, detached: true }) |
||||||
|
server.stdout.pipe(process.stdout) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.on('exit', function (exitCode) { |
||||||
|
console.log("Child exited with code: " + exitCode); |
||||||
|
console.log('end') |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
server.stderr.on('err', function (data) { |
||||||
|
console.log('err', data.toString()) |
||||||
|
}) |
||||||
|
server.stdout.on('data', function (data) { |
||||||
|
console.log('data', data.toString()) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function buildFoundryProject(): Promise<void> { |
||||||
|
console.log('buildFoundryProject', homedir()) |
||||||
|
try { |
||||||
|
const server = spawn('export PATH="' + homedir() + '/.foundry/bin:$PATH" && forge build', [], { cwd: dir + '/hello_foundry', shell: true, detached: true }) |
||||||
|
server.stdout.pipe(process.stdout) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.on('exit', function (exitCode) { |
||||||
|
console.log("Child exited with code: " + exitCode); |
||||||
|
console.log('end') |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
...{}//...process.platform.startsWith('linux') ? tests : {}
|
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
|
||||||
|
const gist_id = '02a847917a6a7ecaf4a7e0d4e68715bf' |
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
'start gist': function (browser: NightwatchBrowser) { |
||||||
|
browser.end() |
||||||
|
/* |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('*[data-id="landingPageImportFromGist"]') |
||||||
|
.click('*[data-id="landingPageImportFromGist"]') |
||||||
|
.waitForElementVisible('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]') |
||||||
|
.execute(function () { |
||||||
|
(document.querySelector('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]') as any).focus() |
||||||
|
}) |
||||||
|
.setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', gist_id) |
||||||
|
.modalFooterOKClick('gisthandler') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewDivtreeViewItemREADME.txt"]') |
||||||
|
}) |
||||||
|
.click('[data-id="treeViewLitreeViewItemcontracts"]') |
||||||
|
.openFile('contracts/3_Ballot.sol') |
||||||
|
.end() |
||||||
|
*/ |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
...tests |
||||||
|
} |
@ -0,0 +1,203 @@ |
|||||||
|
import { ChildProcess, spawn } from "child_process" |
||||||
|
import kill from 'tree-kill' |
||||||
|
import { Nightwatch, NightwatchBrowser } from "nightwatch" |
||||||
|
import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" |
||||||
|
let gitserver: ChildProcess |
||||||
|
|
||||||
|
/* |
||||||
|
/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) |
||||||
|
/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD |
||||||
|
/ GROUP 2: branch operations CREATE & PUBLISH |
||||||
|
/ GROUP 3: file operations rename delete |
||||||
|
*/ |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
after: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform((done) => { |
||||||
|
console.log('kill server', gitserver.pid) |
||||||
|
kill(gitserver.pid) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
gitserver = await spawnGitServer('/tmp/') |
||||||
|
console.log('working directory', process.cwd()) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(5000) |
||||||
|
.waitForElementVisible('*[data-id="cloneButton"]') |
||||||
|
.click('*[data-id="cloneButton"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.click('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') |
||||||
|
.setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') |
||||||
|
.click('[data-id="fileSystem-modal-footer-ok-react"]') |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
.hideToolTips() |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') |
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
.modalFooterOKClick('github-credentials-error') |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
// GROUP 1
|
||||||
|
|
||||||
|
'check file added #group1 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.addFile('test.txt', { content: 'hello world' }, 'README.md') |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue('*[data-id="commitMessage"]', 'testcommit') |
||||||
|
.click('*[data-id="commitButton"]') |
||||||
|
}, |
||||||
|
'look at the commit #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit-ahead"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'sync the commit #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-panel"]') |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
|
||||||
|
.waitForElementVisible('*[data-id="syncButton"]') |
||||||
|
.click('*[data-id="syncButton"]') |
||||||
|
.pause(2000) |
||||||
|
.waitForElementVisible('*[data-id="commitButton"]') |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the log #group1': async function (browser: NightwatchBrowser) { |
||||||
|
const logs = await getGitLog('/tmp/git/bare.git') |
||||||
|
console.log(logs) |
||||||
|
browser.assert.ok(logs.includes('testcommit')) |
||||||
|
}, |
||||||
|
'change a file #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
openFile('test.txt'). |
||||||
|
pause(1000). |
||||||
|
setEditorValue('changes', null) |
||||||
|
}, |
||||||
|
'stage changed file #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='modified-unstaged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.click('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='modified-staged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue('*[data-id="commitMessage"]', 'testcommit2') |
||||||
|
.click('*[data-id="commitButton"]') |
||||||
|
}, |
||||||
|
'push the commit #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-push"]') |
||||||
|
.click('*[data-id="sourcecontrol-push"]') |
||||||
|
.pause(2000) |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit2-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}).pause(2000) |
||||||
|
}, |
||||||
|
'check the log for testcommit2 #group1': async function (browser: NightwatchBrowser) { |
||||||
|
const logs = await getGitLog('/tmp/git/bare.git') |
||||||
|
console.log(logs) |
||||||
|
browser.assert.ok(logs.includes('testcommit2')) |
||||||
|
}, |
||||||
|
'clone locally and add a file and push #group1': async function (browser: NightwatchBrowser) { |
||||||
|
await cloneOnServer('http://localhost:6868/bare.git', '/tmp/') |
||||||
|
await onLocalGitRepoAddFile('/tmp/bare/', 'test2.txt') |
||||||
|
await createCommitOnLocalServer('/tmp/bare/', 'testlocal') |
||||||
|
await onLocalGitRepoPush('/tmp/bare/', 'master') |
||||||
|
}, |
||||||
|
'run a git fetch #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(2000) |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-fetch-branch"]') |
||||||
|
|
||||||
|
.click('*[data-id="sourcecontrol-fetch-branch"]') |
||||||
|
.pause(2000) |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="commits-panel-behind"]') |
||||||
|
.click('*[data-id="commits-panel-behind"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testlocal-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'run pull from the header #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
click('*[data-id="sourcecontrol-button-pull"]') |
||||||
|
.waitForElementNotPresent('*[data-id="commits-panel-behind"]') |
||||||
|
}, |
||||||
|
'check if the file is added #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest2.txt"]') |
||||||
|
}, |
||||||
|
} |
||||||
|
const useIsoGit = process.argv.includes('--use-isogit'); |
||||||
|
if (process.platform.startsWith('win')) { |
||||||
|
module.exports = {} |
||||||
|
} |
||||||
|
else
|
||||||
|
module.exports = { ...tests } |
||||||
|
|
||||||
|
|
@ -0,0 +1,181 @@ |
|||||||
|
import { ChildProcess, spawn } from "child_process" |
||||||
|
import kill from 'tree-kill' |
||||||
|
import { Nightwatch, NightwatchBrowser } from "nightwatch" |
||||||
|
import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" |
||||||
|
let gitserver: ChildProcess |
||||||
|
|
||||||
|
/* |
||||||
|
/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) |
||||||
|
/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD |
||||||
|
/ GROUP 2: branch operations CREATE & PUBLISH |
||||||
|
/ GROUP 3: file operations rename delete |
||||||
|
*/ |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
after: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform((done) => { |
||||||
|
console.log('kill server', gitserver.pid) |
||||||
|
kill(gitserver.pid) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
gitserver = await spawnGitServer('/tmp/') |
||||||
|
console.log('working directory', process.cwd()) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(5000) |
||||||
|
.waitForElementVisible('*[data-id="cloneButton"]') |
||||||
|
.click('*[data-id="cloneButton"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.click('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') |
||||||
|
.setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') |
||||||
|
.click('[data-id="fileSystem-modal-footer-ok-react"]') |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
.hideToolTips() |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') |
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
.modalFooterOKClick('github-credentials-error') |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
// GROUP 2
|
||||||
|
'create a branch #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="branches-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="newbranchname"]') |
||||||
|
.setValue('*[data-id="newbranchname"]', 'testbranch') |
||||||
|
.click('*[data-id="sourcecontrol-create-branch"]') |
||||||
|
.waitForElementVisible('*[data-id="branches-current-branch-testbranch"]') |
||||||
|
.pause(1000) |
||||||
|
}, |
||||||
|
'check if the branch is in the filePanel #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="workspaceGitBranchesDropdown"]') |
||||||
|
.click('[data-id="workspaceGitBranchesDropdown"]') |
||||||
|
.waitForElementVisible('*[data-id="workspaceGit-testbranch"]') |
||||||
|
.expect.element('[data-id="workspaceGit-testbranch"]').text.to.contain('✓ ') |
||||||
|
}, |
||||||
|
'publish the branch #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-panel"]') |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="publishBranchButton"]') |
||||||
|
.pause(2000) |
||||||
|
.waitForElementNotVisible('*[data-id="publishBranchButton"]') |
||||||
|
}, |
||||||
|
'check if the branch is published #group2': async function (browser: NightwatchBrowser) { |
||||||
|
const branches = await getBranches('/tmp/git/bare.git') |
||||||
|
browser.assert.ok(branches.includes('testbranch')) |
||||||
|
}, |
||||||
|
'add file to new branch #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.addFile('test.txt', { content: 'hello world' }, 'README.md') |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(2000) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue('*[data-id="commitMessage"]', 'testcommit') |
||||||
|
.click('*[data-id="commitButton"]') |
||||||
|
.pause(1000) |
||||||
|
}, |
||||||
|
'check if the commit is ahead in the branches list #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="branches-panel"]') |
||||||
|
.click('*[data-id="branches-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="branches-current-branch-testbranch"]') |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-current-branch-testbranch']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
suppressNotFoundErrors: true |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='commits-panel-ahead']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
suppressNotFoundErrors: true |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branchdifference-commits-testbranch-ahead']//*[@data-id='commit-summary-testcommit-ahead']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branchdifference-commits-testbranch-ahead']//*[@data-id='commit-change-added-test.txt']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='local-branch-commits-testbranch']//*[@data-id='commit-summary-testcommit-ahead']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='local-branch-commits-testbranch']//*[@data-id='commit-change-added-test.txt']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
}, |
||||||
|
'switch back to master #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-toggle-branch-master']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-toggle-current-branch-master']", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check if test file is gone #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.txt"]') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const useIsoGit = process.argv.includes('--useIsoGit'); |
||||||
|
if (process.platform.startsWith('win')) { |
||||||
|
module.exports = {} |
||||||
|
} |
||||||
|
else
|
||||||
|
module.exports = { ...tests } |
@ -0,0 +1,153 @@ |
|||||||
|
import { ChildProcess, spawn } from "child_process" |
||||||
|
import kill from 'tree-kill' |
||||||
|
import { Nightwatch, NightwatchBrowser } from "nightwatch" |
||||||
|
import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" |
||||||
|
let gitserver: ChildProcess |
||||||
|
|
||||||
|
/* |
||||||
|
/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) |
||||||
|
/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD |
||||||
|
/ GROUP 2: branch operations CREATE & PUBLISH |
||||||
|
/ GROUP 3: file operations rename delete |
||||||
|
*/ |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
after: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform((done) => { |
||||||
|
console.log('kill server', gitserver.pid) |
||||||
|
kill(gitserver.pid) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
gitserver = await spawnGitServer('/tmp/') |
||||||
|
console.log('working directory', process.cwd()) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(5000) |
||||||
|
.waitForElementVisible('*[data-id="cloneButton"]') |
||||||
|
.click('*[data-id="cloneButton"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.click('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') |
||||||
|
.setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') |
||||||
|
.click('[data-id="fileSystem-modal-footer-ok-react"]') |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
.hideToolTips() |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') |
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
clickLaunchIcon('dgit') |
||||||
|
.saveScreenshot('./reports/screenshots/gitui.png') |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.saveScreenshot('./reports/screenshots/gitui2.png') |
||||||
|
.pause(1000) |
||||||
|
.saveScreenshot('./reports/screenshots/gitui3.png') |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
.pause(1000) |
||||||
|
.modalFooterOKClick('github-credentials-error') |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
'check file added #group1 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.addFile('test.txt', { content: 'hello world' }, 'README.md') |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue('*[data-id="commitMessage"]', 'testcommit') |
||||||
|
.click('*[data-id="commitButton"]') |
||||||
|
}, |
||||||
|
|
||||||
|
// group 3
|
||||||
|
'rename a file #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.txt"]') |
||||||
|
.click('*[data-id="treeViewLitreeViewItemtest.txt"]') |
||||||
|
.renamePath('test.txt', 'test_rename', 'test_rename.txt') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest_rename.txt"]') |
||||||
|
.pause(1000) |
||||||
|
}, |
||||||
|
'stage renamed file #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='deleted-unstaged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='new-untracked' and @data-file='/test_rename.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(2000) |
||||||
|
.click('*[data-id="sourcecontrol-add-all"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='added-staged' and @data-file='/test_rename.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'undo the rename #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="unStageStagedtest_rename.txt"]') |
||||||
|
.click('*[data-id="unStageStagedtest_rename.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="unDoStagedtest.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementNotPresent({ |
||||||
|
selector: "//*[@data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check if file is returned #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.txt"]') |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const useIsoGit = process.argv.includes('--use-isogit'); |
||||||
|
if (process.platform.startsWith('win')) { |
||||||
|
module.exports = {} |
||||||
|
} |
||||||
|
else
|
||||||
|
module.exports = { ...tests } |
@ -0,0 +1,200 @@ |
|||||||
|
import { ChildProcess, spawn } from "child_process" |
||||||
|
import kill from 'tree-kill' |
||||||
|
import { Nightwatch, NightwatchBrowser } from "nightwatch" |
||||||
|
import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" |
||||||
|
let gitserver: ChildProcess |
||||||
|
|
||||||
|
/* |
||||||
|
/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) |
||||||
|
/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD |
||||||
|
/ GROUP 2: branch operations CREATE & PUBLISH |
||||||
|
/ GROUP 3: file operations rename delete |
||||||
|
*/ |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
after: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform((done) => { |
||||||
|
console.log('kill server', gitserver.pid) |
||||||
|
kill(gitserver.pid) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
gitserver = await spawnGitServer('/tmp/') |
||||||
|
console.log('working directory', process.cwd()) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(5000) |
||||||
|
.waitForElementVisible('*[data-id="cloneButton"]') |
||||||
|
.click('*[data-id="cloneButton"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.click('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') |
||||||
|
.setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') |
||||||
|
.click('[data-id="fileSystem-modal-footer-ok-react"]') |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
.hideToolTips() |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') |
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
.pause(1000) |
||||||
|
.modalFooterOKClick('github-credentials-error') |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
// GROUP 1
|
||||||
|
|
||||||
|
'check file added #group1 #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.addFile('test.txt', { content: 'hello world' }, 'README.md') |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="addToGitChangestest.txt"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue('*[data-id="commitMessage"]', 'testcommit') |
||||||
|
.click('*[data-id="commitButton"]') |
||||||
|
}, |
||||||
|
'look at the commit #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit-ahead"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'add second remote #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="add-manual-remoteurl"]') |
||||||
|
.setValue('*[data-id="add-manual-remoteurl"]', 'http://localhost:6868/bare2.git') |
||||||
|
.waitForElementVisible('*[data-id="add-manual-remotename"]') |
||||||
|
.setValue('*[data-id="add-manual-remotename"]', 'origin2') |
||||||
|
.waitForElementVisible('*[data-id="add-manual-remotebtn"]') |
||||||
|
.click('*[data-id="add-manual-remotebtn"]') |
||||||
|
}, |
||||||
|
'check the buttons #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="default-remote-check-origin"]') |
||||||
|
.waitForElementVisible('*[data-id="set-as-default-origin2"]') |
||||||
|
}, |
||||||
|
'check the commands #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'switch to origin2 #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="set-as-default-origin2"]') |
||||||
|
.click('*[data-id="set-as-default-origin2"]') |
||||||
|
}, |
||||||
|
'check the commands for origin2 #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin2')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'sync the commit #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-panel"]') |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="syncButton"]') |
||||||
|
.click('*[data-id="syncButton"]') |
||||||
|
.waitForElementVisible('*[data-id="commitButton"]') |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the log #group4': async function (browser: NightwatchBrowser) { |
||||||
|
const logs = await getGitLog('/tmp/git/bare2.git') |
||||||
|
console.log(logs) |
||||||
|
browser.assert.ok(logs.includes('testcommit')) |
||||||
|
const logs2 = await getGitLog('/tmp/git/bare.git') |
||||||
|
console.log(logs2) |
||||||
|
console.log(logs2.includes('testcommit3')) |
||||||
|
browser.assert.ok(logs2.includes('testcommit3')) |
||||||
|
}, |
||||||
|
'switch to origin #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(5000) |
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="set-as-default-origin"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="set-as-default-origin"]') |
||||||
|
}, |
||||||
|
'check the commands for origin #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the commit ahead #group4': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="sourcecontrol-panel"]') |
||||||
|
.click('*[data-id="sourcecontrol-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="syncButton"]') |
||||||
|
// do not sync
|
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.waitForElementPresent({ |
||||||
|
selector: '//*[@data-id="commit-summary-testcommit-ahead"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
const useIsoGit = process.argv.includes('--use-isogit'); |
||||||
|
if (process.platform.startsWith('win')) { |
||||||
|
module.exports = {} |
||||||
|
} |
||||||
|
else
|
||||||
|
module.exports = { ...tests } |
@ -0,0 +1,28 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
'@isogit': true, |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
'clone a repo': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromGit"]') |
||||||
|
.click('button[data-id="landingPageImportFromGit"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.click('[data-id="fileSystemModalDialogModalBody-react"]') |
||||||
|
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') |
||||||
|
.setValue('[data-id="modalDialogCustomPromptTextClone"]', 'https://github.com/ethereum/awesome-remix') |
||||||
|
.click('[data-id="fileSystem-modal-footer-ok-react"]') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
}) |
||||||
|
.end() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,255 @@ |
|||||||
|
import { NightwatchBrowser } from "nightwatch" |
||||||
|
|
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
|
||||||
|
'open default template': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.click('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.waitForElementPresent('*[data-id="create-remixDefault"]') |
||||||
|
.scrollAndClick('*[data-id="create-remixDefault"]') |
||||||
|
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') |
||||||
|
.waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="initgit-btn"]') |
||||||
|
.click('*[data-id="initgit-btn"]') |
||||||
|
.waitForElementNotPresent('*[data-id="initgit-btn"]') |
||||||
|
}, |
||||||
|
'launch github login via FE #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="filepanel-login-github"]') |
||||||
|
.click('*[data-id="filepanel-login-github"]') |
||||||
|
}, |
||||||
|
'login to github #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="gitubUsername"]') |
||||||
|
.setValue('*[data-id="githubToken"]', process.env.dgit_token) |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
}, |
||||||
|
'check if the settings are loaded #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="connected-as-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-img-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-link-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="remotes-panel"]') |
||||||
|
}, |
||||||
|
'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="filepanel-connected-img-bunsenstraat"]') |
||||||
|
}, |
||||||
|
'clone a repository #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.click('*[data-id="clone-panel"]') |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@data-id="fetch-repositories"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@id="repository-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@id="repository-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[contains(text(), "awesome-remix")]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[contains(text(), "awesome-remix")]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@id="branch-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@id="branch-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[contains(text(), "master")]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@data-id="clonebtn-ethereum/awesome-remix-master"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="clone-panel-content"]//*[@data-id="clonebtn-ethereum/awesome-remix-master"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[2]) |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check if there is a README.md file #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') |
||||||
|
}, |
||||||
|
'check the commands panel #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'master')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'master')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the remotes #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
|
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="remotes-panel-content"]') |
||||||
|
.pause(2000) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-origin-default"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-current-branch-master"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-sync-origin"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]', |
||||||
|
locateStrategy: 'xpath', |
||||||
|
timeout: 10000 |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'check the commits of branch links #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="commit-summary-linking fixed-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'switch to branch links #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="branches-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-toggle-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-toggle-current-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the local branches #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="branches-panel-content-local-branches"]//*[@data-id="branches-toggle-current-branch-links"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the local commits #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="commits-current-branch-links"]//*[@data-id="commit-summary-linking fixed-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="commits-current-branch-links"]//*[@data-id="commit-summary-linking fixed-"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="commits-current-branch-links"]//*[@data-id="commit-change-modified-README.md"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the commands panel for links #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'links')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'links')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'disconnect github #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="disconnect-github"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="disconnect-github"]') |
||||||
|
.waitForElementNotPresent('*[data-id="connected-as-bunsenstraat"]') |
||||||
|
}, |
||||||
|
'check the FE for the disconnected auth user #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementNotPresent('*[data-id="filepanel-connected-img-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="filepanel-login-github"]') |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = tests |
@ -0,0 +1,190 @@ |
|||||||
|
import { NightwatchBrowser } from "nightwatch" |
||||||
|
|
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
|
||||||
|
'open default template': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.click('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.waitForElementPresent('*[data-id="create-remixDefault"]') |
||||||
|
.scrollAndClick('*[data-id="create-remixDefault"]') |
||||||
|
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') |
||||||
|
.waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="initgit-btn"]') |
||||||
|
.click('*[data-id="initgit-btn"]') |
||||||
|
.waitForElementNotPresent('*[data-id="initgit-btn"]') |
||||||
|
}, |
||||||
|
'launch github login via FE #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="filepanel-login-github"]') |
||||||
|
.click('*[data-id="filepanel-login-github"]') |
||||||
|
}, |
||||||
|
'login to github #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="gitubUsername"]') |
||||||
|
.setValue('*[data-id="githubToken"]', process.env.dgit_token) |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
}, |
||||||
|
'check if the settings are loaded #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="connected-as-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-img-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-link-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="remotes-panel"]') |
||||||
|
}, |
||||||
|
'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="filepanel-connected-img-bunsenstraat"]') |
||||||
|
}, |
||||||
|
'add a remote #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="remotes-panel"]') |
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="fetch-repositories"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@id="repository-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@id="repository-select"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[contains(text(), "awesome-remix")]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[contains(text(), "awesome-remix")]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-remotename"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.setValue({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-remotename"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}, 'newremote') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-addremote"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-addremote"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-newremote-default"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the commands panel for newremote #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'newremote')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.getAttribute({ |
||||||
|
selector: '//*[@data-id="sourcecontrol-pull"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}, 'disabled', (result) => { |
||||||
|
if (result.value) { |
||||||
|
browser.assert.fail('Button is disabled') |
||||||
|
} else { |
||||||
|
browser.assert.ok(true) |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
'remove the remote #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="remotes-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-rm-newremote"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(2000) |
||||||
|
.click({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-rm-newremote"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.waitForElementNotPresent({ |
||||||
|
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-newremote-default"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
}, |
||||||
|
'check the commands panel for removed remote #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="commands-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementNotPresent({ |
||||||
|
selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'newremote')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.getAttribute({ |
||||||
|
selector: '//*[@data-id="sourcecontrol-pull"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}, 'disabled', (result) => { |
||||||
|
if (result.value) { |
||||||
|
browser.assert.ok(true) |
||||||
|
} else { |
||||||
|
browser.assert.fail('Button is not disabled') |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = tests |
@ -0,0 +1,180 @@ |
|||||||
|
import { NightwatchBrowser } from "nightwatch" |
||||||
|
|
||||||
|
const useIsoGit = process.argv.includes('--use-isogit'); |
||||||
|
let commitCount = 0 |
||||||
|
let branchCount = 0 |
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
browser.hideToolTips() |
||||||
|
done() |
||||||
|
}, |
||||||
|
|
||||||
|
'open default template': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.click('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.waitForElementPresent('*[data-id="create-remixDefault"]') |
||||||
|
.scrollAndClick('*[data-id="create-remixDefault"]') |
||||||
|
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') |
||||||
|
.waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'Update settings for git #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="initgit-btn"]') |
||||||
|
.click('*[data-id="initgit-btn"]') |
||||||
|
.waitForElementNotPresent('*[data-id="initgit-btn"]') |
||||||
|
}, |
||||||
|
'launch github login via FE #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="filepanel-login-github"]') |
||||||
|
.click('*[data-id="filepanel-login-github"]') |
||||||
|
}, |
||||||
|
'login to github #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="gitubUsername"]') |
||||||
|
.setValue('*[data-id="githubToken"]', process.env.dgit_token) |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
}, |
||||||
|
'check if the settings are loaded #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="connected-as-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-img-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="connected-link-bunsenstraat"]') |
||||||
|
.waitForElementVisible('*[data-id="remotes-panel"]') |
||||||
|
}, |
||||||
|
'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible('*[data-id="filepanel-connected-img-bunsenstraat"]') |
||||||
|
}, |
||||||
|
// pagination test
|
||||||
|
'clone repo #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="clone-panel"]') |
||||||
|
.click('*[data-id="clone-panel"]') |
||||||
|
.waitForElementVisible('*[data-id="clone-url"]') |
||||||
|
.setValue('*[data-id="clone-url"]', 'https://github.com/yann300/remix-reward') |
||||||
|
.waitForElementVisible('*[data-id="clone-branch"]') |
||||||
|
.setValue('*[data-id="clone-branch"]', 'master') |
||||||
|
.waitForElementVisible('*[data-id="clone-btn"]') |
||||||
|
.click('*[data-id="clone-btn"]') |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.pause(5000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[2]) |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Update settings for git #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser. |
||||||
|
clickLaunchIcon('dgit') |
||||||
|
.waitForElementVisible('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="github-panel"]') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubToken"]', 'invalidtoken') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="gitubUsername"]', 'git') |
||||||
|
.pause(1000) |
||||||
|
.setValue('*[data-id="githubEmail"]', 'git@example.com') |
||||||
|
.pause(1000) |
||||||
|
.click('*[data-id="saveGitHubCredentials"]') |
||||||
|
.pause(1000) |
||||||
|
.modalFooterOKClick('github-credentials-error') |
||||||
|
}, |
||||||
|
'check the commits panel for pagination #group3': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="commits-panel"]') |
||||||
|
.click('*[data-id="commits-panel"]') |
||||||
|
.elements('xpath', '//*[@data-id="commits-current-branch-master"]//*[@data-type="commit-summary"]', function (result) { |
||||||
|
console.log('Number of commit-summary elements:', (result.value as any).length); |
||||||
|
if (useIsoGit) { |
||||||
|
commitCount = (result.value as any).length |
||||||
|
browser.assert.ok((result.value as any).length == 1) |
||||||
|
} else { |
||||||
|
commitCount = (result.value as any).length |
||||||
|
browser.assert.ok((result.value as any).length > 2) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
'load more commits #group3': function (browser: NightwatchBrowser) { |
||||||
|
console.log('commitCount:', commitCount) |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="load-more-commits"]') |
||||||
|
.click('*[data-id="load-more-commits"]') |
||||||
|
.waitForElementVisible('*[data-id="loader-indicator"]') |
||||||
|
.waitForElementNotPresent('*[data-id="loader-indicator"]') |
||||||
|
.pause(2000) |
||||||
|
.elements('xpath', '//*[@data-id="commits-current-branch-master"]//*[@data-type="commit-summary"]', function (result) { |
||||||
|
console.log('Number of commit-summary elements:', (result.value as any).length); |
||||||
|
browser.assert.ok((result.value as any).length > commitCount) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'load more branches from remote #group3': function (browser: NightwatchBrowser) { |
||||||
|
|
||||||
|
browser |
||||||
|
.click('*[data-id="branches-panel"]') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '//*[@data-id="branches-panel-content-remote-branches"]', |
||||||
|
locateStrategy: 'xpath' |
||||||
|
}) |
||||||
|
.elements('xpath', '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-type="branches-branch"]', function (result) { |
||||||
|
console.log('Number of branches elements:', (result.value as any).length); |
||||||
|
if (useIsoGit) { |
||||||
|
branchCount = (result.value as any).length |
||||||
|
browser.assert.ok((result.value as any).length == 1) |
||||||
|
} else { |
||||||
|
branchCount = (result.value as any).length |
||||||
|
browser.assert.ok((result.value as any).length > 2) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
if (useIsoGit) { |
||||||
|
|
||||||
|
browser.waitForElementVisible('*[data-id="remote-sync-origin"]') |
||||||
|
.click('*[data-id="remote-sync-origin"]') |
||||||
|
.waitForElementVisible('*[data-id="loader-indicator"]') |
||||||
|
.waitForElementNotPresent('*[data-id="loader-indicator"]') |
||||||
|
.pause(2000) |
||||||
|
.elements('xpath', '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-type="branches-branch"]', function (result) { |
||||||
|
console.log('Number of branches elements:', (result.value as any).length); |
||||||
|
browser.assert.ok((result.value as any).length > branchCount) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
browser.waitForElementVisible('*[data-id="show-more-branches-on-remote"]') |
||||||
|
.click('*[data-id="show-more-branches-on-remote"]') |
||||||
|
.pause(1000) |
||||||
|
.elements('xpath', '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-type="branches-branch"]', function (result) { |
||||||
|
console.log('Number of branches elements:', (result.value as any).length); |
||||||
|
browser.assert.ok((result.value as any).length > branchCount) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = tests |
@ -0,0 +1,90 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
import { ChildProcess, spawn, execSync } from 'child_process' |
||||||
|
import { homedir } from 'os' |
||||||
|
import path from 'path' |
||||||
|
import os from 'os' |
||||||
|
|
||||||
|
const dir = path.join('remix-desktop-test-' + Date.now().toString()) |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
setuphardhat: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
await setupHardhatProject() |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
addScript: function (browser: NightwatchBrowser) { |
||||||
|
// run script in console
|
||||||
|
browser.executeAsync(function (dir, done) { |
||||||
|
(window as any).electronAPI.openFolderInSameWindow('/tmp/' + dir).then(done) |
||||||
|
}, [dir], () => { |
||||||
|
console.log('done window opened') |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewDivDraggableItemhardhat.config.js"]', 10000) |
||||||
|
}, |
||||||
|
compile: function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
console.log('generating compilation result') |
||||||
|
await compileHardhatProject() |
||||||
|
done() |
||||||
|
}) |
||||||
|
.expect.element('*[data-id="terminalJournal"]').text.to.contain('receiving compilation result from Hardhat').before(60000) |
||||||
|
let addressRef |
||||||
|
browser.clickLaunchIcon('filePanel') |
||||||
|
.openFile('contracts') |
||||||
|
.openFile('contracts/Token.sol') |
||||||
|
.clickLaunchIcon('udapp') |
||||||
|
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') |
||||||
|
.selectContract('Token') |
||||||
|
.createContract('') |
||||||
|
.clickInstance(0) |
||||||
|
.clickFunction('balanceOf - call', { types: 'address account', values: '0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c' }) |
||||||
|
.getAddressAtPosition(0, (address) => { |
||||||
|
addressRef = address |
||||||
|
}) |
||||||
|
.perform((done) => { |
||||||
|
browser.verifyCallReturnValue(addressRef, ['0:uint256: 1000000']) |
||||||
|
.perform(() => done()) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function compileHardhatProject(): Promise<void> { |
||||||
|
console.log(process.cwd()) |
||||||
|
try { |
||||||
|
const server = spawn('npx hardhat compile', [], { cwd: '/tmp/' + dir, shell: true, detached: true }) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.on('exit', function (exitCode) { |
||||||
|
console.log("Child exited with code: " + exitCode); |
||||||
|
console.log('end') |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function setupHardhatProject(): Promise<void> { |
||||||
|
console.log('setup hardhat project', dir) |
||||||
|
try { |
||||||
|
const server = spawn(`git clone https://github.com/NomicFoundation/hardhat-boilerplate ${dir} && cd ${dir} && yarn install && yarn add "@typechain/ethers-v5@^10.1.0" && yarn add "@typechain/hardhat@^6.1.2" && yarn add "typechain@^8.1.0" && echo "END"`, [], { cwd: '/tmp/', shell: true, detached: true }) |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
server.on('exit', function (exitCode) { |
||||||
|
console.log("Child exited with code: " + exitCode); |
||||||
|
console.log('end') |
||||||
|
resolve() |
||||||
|
}) |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
...tests |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
'@offline': true, |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
'open default template': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.click('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.waitForElementPresent('*[data-id="create-remixDefault"]') |
||||||
|
.scrollAndClick('*[data-id="create-remixDefault"]') |
||||||
|
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') |
||||||
|
.waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
.click('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]') |
||||||
|
.click('*[data-id="treeViewLitreeViewItemcontracts"]') |
||||||
|
.waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]') |
||||||
|
.openFile('contracts/1_Storage.sol') |
||||||
|
.waitForElementVisible('*[id="editorView"]', 10000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('function retrieve() public view returns (uint256){')) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'compile storage': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="compilerContainerCompileBtn"]') |
||||||
|
.click('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.pause(5000) |
||||||
|
.waitForElementPresent('*[data-id="compiledContracts"] option', 60000) |
||||||
|
.click('*[data-id="compilation-details"]') |
||||||
|
.waitForElementVisible('*[data-id="remixui_treeviewitem_metadata"]') |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,269 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
'open default template': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.click('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.waitForElementPresent('*[data-id="create-remixDefault"]') |
||||||
|
.scrollAndClick('*[data-id="create-remixDefault"]') |
||||||
|
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') |
||||||
|
.waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
.click('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]') |
||||||
|
.click('*[data-id="treeViewLitreeViewItemcontracts"]') |
||||||
|
.waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]') |
||||||
|
.openFile('contracts/1_Storage.sol') |
||||||
|
.waitForElementVisible('*[id="editorView"]', 10000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('function retrieve() public view returns (uint256){')) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Should find text #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]') |
||||||
|
.click('*[plugin="search"]').waitForElementVisible('*[id="search_input"]') |
||||||
|
.waitForElementVisible('*[id="search_include"]') |
||||||
|
.setValue('*[id="search_include"]', ', *.*').pause(2000) |
||||||
|
.setValue('*[id="search_input"]', 'read').sendKeys('*[id="search_input"]', browser.Keys.ENTER) |
||||||
|
.pause(1000) |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', '3_BALLOT.SOL', 60000) |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', 'contracts', 60000) |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', 'README.TXT', 60000) |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', 'file must') |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', 'be compiled') |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', 'that person al') |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', 'sender.voted') |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', 'read') |
||||||
|
.elements('css selector', '.search_plugin_search_line', (res) => { |
||||||
|
Array.isArray(res.value) && browser.assert.equal(res.value.length, 6) |
||||||
|
}) |
||||||
|
}, 'Should find text with exclude #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clearValue('*[id="search_input"]') |
||||||
|
.setValue('*[id="search_input"]', 'contract').pause(1000) |
||||||
|
.clearValue('*[id="search_include"]').pause(2000) |
||||||
|
.setValue('*[id="search_include"]', '**').sendKeys('*[id="search_include"]', browser.Keys.ENTER).pause(4000) |
||||||
|
.elements('css selector', '.search_plugin_search_line', (res) => { |
||||||
|
Array.isArray(res.value) && browser.assert.equal(res.value.length, 62) |
||||||
|
}) |
||||||
|
.setValue('*[id="search_exclude"]', ',contracts/**').sendKeys('*[id="search_exclude"]', browser.Keys.ENTER).pause(4000) |
||||||
|
.elements('css selector', '.search_plugin_search_line', (res) => { |
||||||
|
Array.isArray(res.value) && browser.assert.equal(res.value.length, 56) |
||||||
|
}) |
||||||
|
.clearValue('*[id="search_include"]').setValue('*[id="search_include"]', '*.sol, *.js, *.txt') |
||||||
|
.clearValue('*[id="search_exclude"]').setValue('*[id="search_exclude"]', '.*/**/*') |
||||||
|
}, |
||||||
|
'Should find regex #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[id="search_input"]') |
||||||
|
.clearValue('*[id="search_input"]').pause(2000) |
||||||
|
.setValue('*[id="search_input"]', '^contract').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(3000) |
||||||
|
.waitForElementVisible('*[data-id="search_use_regex"]').click('*[data-id="search_use_regex"]').pause(3000) |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', '3_BALLOT.SOL', 60000) |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', '2_OWNER.SOL', 60000) |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', '1_STORAGE.SOL', 60000) |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', 'BALLOT_TEST.SOL', 60000) |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', 'tests', 60000) |
||||||
|
.elements('css selector', '.search_plugin_search_line', (res) => { |
||||||
|
Array.isArray(res.value) && browser.assert.equal(res.value.length, 4) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Should find matchcase #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="search_use_regex"]').click('*[data-id="search_use_regex"]') |
||||||
|
.waitForElementVisible('*[data-id="search_case_sensitive"]').click('*[data-id="search_case_sensitive"]').pause(4000) |
||||||
|
.elements('css selector', '.search_plugin_search_line', (res) => { |
||||||
|
Array.isArray(res.value) && browser.assert.equal(res.value.length, 0) |
||||||
|
}) |
||||||
|
.clearValue('*[id="search_input"]') |
||||||
|
.setValue('*[id="search_input"]', 'Contract').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(3000) |
||||||
|
.elements('css selector', '.search_plugin_search_line', (res) => { |
||||||
|
Array.isArray(res.value) && browser.assert.equal(res.value.length, 3) |
||||||
|
}) |
||||||
|
.waitForElementContainsText('*[data-id="search_results"]', 'STORAGE.TEST.JS', 60000) |
||||||
|
}, |
||||||
|
'Should find matchword #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="search_case_sensitive"]').click('*[data-id="search_case_sensitive"]') |
||||||
|
.waitForElementVisible('*[data-id="search_whole_word"]').click('*[data-id="search_whole_word"]').pause(2000) |
||||||
|
.clearValue('*[id="search_input"]') |
||||||
|
.setValue('*[id="search_input"]', 'contract').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(4000) |
||||||
|
.elements('css selector', '.search_plugin_search_line', (res) => { |
||||||
|
Array.isArray(res.value) && browser.assert.equal(res.value.length, 15) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Should replace text #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="toggle_replace"]').click('*[data-id="toggle_replace"]') |
||||||
|
.waitForElementVisible('*[id="search_replace"]') |
||||||
|
.clearValue('*[id="search_include"]').setValue('*[id="search_include"]', 'contracts/2_*.sol') |
||||||
|
.setValue('*[id="search_replace"]', 'replacing').sendKeys('*[id="search_include"]', browser.Keys.ENTER).pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="contracts/2_Owner.sol-33-71"]') |
||||||
|
.moveToElement('*[data-id="contracts/2_Owner.sol-33-71"]', 10, 10) |
||||||
|
.waitForElementVisible('*[data-id="replace-contracts/2_Owner.sol-33-71"]') |
||||||
|
.click('*[data-id="replace-contracts/2_Owner.sol-33-71"]').pause(2000). |
||||||
|
modalFooterOKClick('confirmreplace').pause(2000). |
||||||
|
getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('replacing deployer for a constructor'), 'should replace text ok') |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Should replace text without confirmation #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser.click('*[data-id="confirm_replace_label"]').pause(500) |
||||||
|
.clearValue('*[id="search_input"]') |
||||||
|
.setValue('*[id="search_input"]', 'replacing').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(1000) |
||||||
|
.setValue('*[id="search_replace"]', 'replacing2').pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="contracts/2_Owner.sol-33-71"]') |
||||||
|
.moveToElement('*[data-id="contracts/2_Owner.sol-33-71"]', 10, 10) |
||||||
|
.waitForElementVisible('*[data-id="replace-contracts/2_Owner.sol-33-71"]') |
||||||
|
.click('*[data-id="replace-contracts/2_Owner.sol-33-71"]').pause(2000). |
||||||
|
getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('replacing2 deployer for a constructor'), 'should replace text ok') |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Should replace all & undo #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clearValue('*[id="search_input"]') |
||||||
|
.clearValue('*[id="search_include"]').setValue('*[id="search_include"]', 'contracts/1_*.sol') |
||||||
|
.setValue('*[id="search_input"]', 'storage').sendKeys('*[id="search_include"]', browser.Keys.ENTER) |
||||||
|
.clearValue('*[id="search_replace"]') |
||||||
|
.setValue('*[id="search_replace"]', '123test').pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="replace-all-contracts/1_Storage.sol"]') |
||||||
|
.click('*[data-id="replace-all-contracts/1_Storage.sol"]').pause(2000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('contract 123test'), 'should replace text ok') |
||||||
|
browser.assert.ok(content.includes('title 123test'), 'should replace text ok') |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="undo-replace-contracts/1_Storage.sol"]') |
||||||
|
.click('*[data-id="undo-replace-contracts/1_Storage.sol"]').pause(2000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('contract Storage'), 'should undo text ok') |
||||||
|
browser.assert.ok(content.includes('title Storage'), 'should undo text ok') |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Should replace all & undo & switch between files #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser.waitForElementVisible('*[id="search_input"]') |
||||||
|
.clearValue('*[id="search_input"]') |
||||||
|
.clearValue('*[id="search_include"]').setValue('*[id="search_include"]', '*.sol, *.js, *.txt') |
||||||
|
.setValue('*[id="search_input"]', 'storage').sendKeys('*[id="search_include"]', browser.Keys.ENTER) |
||||||
|
.clearValue('*[id="search_replace"]') |
||||||
|
.setValue('*[id="search_replace"]', '123test').pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="replace-all-contracts/1_Storage.sol"]') |
||||||
|
.click('*[data-id="replace-all-contracts/1_Storage.sol"]').pause(2000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('contract 123test'), 'should replace text ok') |
||||||
|
browser.assert.ok(content.includes('title 123test'), 'should replace text ok') |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="undo-replace-contracts/1_Storage.sol"]') |
||||||
|
.openFile('README.txt') |
||||||
|
.click('*[plugin="search"]').pause(2000) |
||||||
|
.waitForElementNotPresent('*[data-id="undo-replace-contracts/1_Storage.sol"]') |
||||||
|
.waitForElementVisible('*[data-id="replace-all-README.txt"]') |
||||||
|
.click('*[data-id="replace-all-README.txt"]').pause(2000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes("123test' contract"), 'should replace text ok') |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="undo-replace-README.txt"]') |
||||||
|
.click('div[data-path="/contracts/1_Storage.sol"]').pause(2000) |
||||||
|
.waitForElementVisible('*[data-id="undo-replace-contracts/1_Storage.sol"]') |
||||||
|
.click('*[data-id="undo-replace-contracts/1_Storage.sol"]').pause(2000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('contract Storage'), 'should undo text ok') |
||||||
|
browser.assert.ok(content.includes('title Storage'), 'should undo text ok') |
||||||
|
}) |
||||||
|
.click('div[data-path="/README.txt"]').pause(2000) |
||||||
|
.waitForElementVisible('*[data-id="undo-replace-README.txt"]') |
||||||
|
.click('*[data-id="undo-replace-README.txt"]').pause(2000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes("Storage' contract"), 'should replace text ok') |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Should hide button when edited content is the same #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser.refresh() |
||||||
|
.waitForElementVisible('*[data-id="remixIdeSidePanel"]') |
||||||
|
.addFile('test.sol', { content: '123' }) |
||||||
|
.pause(4000) |
||||||
|
.click('*[plugin="search"]') |
||||||
|
.waitForElementVisible('*[id="search_input"]') |
||||||
|
.waitForElementVisible('*[data-id="toggle_replace"]') |
||||||
|
.click('*[data-id="toggle_replace"]') |
||||||
|
.clearValue('*[id="search_input"]') |
||||||
|
.setValue('*[id="search_input"]', '123') |
||||||
|
.sendKeys('*[id="search_input"]', browser.Keys.ENTER) |
||||||
|
.waitForElementVisible('*[id="search_replace"]') |
||||||
|
.clearValue('*[id="search_replace"]') |
||||||
|
.setValue('*[id="search_replace"]', '456').pause(1000) |
||||||
|
.click('*[data-id="confirm_replace_label"]').pause(500) |
||||||
|
.waitForElementVisible('*[data-id="replace-all-test.sol"]') |
||||||
|
.click('*[data-id="replace-all-test.sol"]').pause(2000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('456'), 'should replace text ok') |
||||||
|
} |
||||||
|
) |
||||||
|
.setEditorValue('123') |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('123'), 'should have text ok') |
||||||
|
} |
||||||
|
).pause(5000) |
||||||
|
.waitForElementNotPresent('*[data-id="undo-replace-test.sol"]') |
||||||
|
}, |
||||||
|
'Should disable/enable button when edited content changed #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[id="search_input"]') |
||||||
|
.clearValue('*[id="search_input"]') |
||||||
|
.clearValue('*[id="search_input"]') |
||||||
|
.setValue('*[id="search_input"]', '123').sendKeys('*[id="search_input"]', browser.Keys.ENTER) |
||||||
|
.clearValue('*[id="search_replace"]') |
||||||
|
.setValue('*[id="search_replace"]', 'replaced').pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="replace-all-test.sol"]') |
||||||
|
.click('*[data-id="replace-all-test.sol"]').pause(2000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('replaced'), 'should replace text ok') |
||||||
|
} |
||||||
|
) |
||||||
|
.setEditorValue('changed') |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('changed'), 'should have text ok') |
||||||
|
} |
||||||
|
).pause(5000) |
||||||
|
.waitForElementVisible('*[data-id="undo-replace-test.sol"]') |
||||||
|
.getAttribute('[data-id="undo-replace-test.sol"]', 'disabled', (result) => { |
||||||
|
browser.assert.equal(result.value, 'true', 'should be disabled') |
||||||
|
}) |
||||||
|
.setEditorValue('replaced') |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('replaced'), 'should have text ok') |
||||||
|
} |
||||||
|
).pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="undo-replace-test.sol"]') |
||||||
|
.getAttribute('[data-id="undo-replace-test.sol"]', 'disabled', (result) => { |
||||||
|
browser.assert.equal(result.value, null, 'should not be disabled') |
||||||
|
}) |
||||||
|
.click('*[data-id="undo-replace-test.sol"]').pause(2000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('123'), 'should have text ok') |
||||||
|
}) |
||||||
|
.waitForElementNotPresent('*[data-id="undo-replace-test.sol"]') |
||||||
|
}, |
||||||
|
|
||||||
|
'should clear search #group2': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[id="search_input"]') |
||||||
|
.setValue('*[id="search_input"]', 'nodata').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(1000) |
||||||
|
.elements('css selector', '.search_plugin_search_line', (res) => { |
||||||
|
Array.isArray(res.value) && browser.assert.equal(res.value.length, 0) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
import {NightwatchBrowser} from 'nightwatch' |
||||||
|
import { ChildProcess, spawn, execSync } from 'child_process' |
||||||
|
import { homedir } from 'os' |
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
open: function (browser: NightwatchBrowser) { |
||||||
|
browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') |
||||||
|
}, |
||||||
|
|
||||||
|
'open default template': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.click('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.waitForElementPresent('*[data-id="create-remixDefault"]') |
||||||
|
.scrollAndClick('*[data-id="create-remixDefault"]') |
||||||
|
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') |
||||||
|
.waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
.click('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]') |
||||||
|
.click('*[data-id="treeViewLitreeViewItemcontracts"]') |
||||||
|
.waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]') |
||||||
|
.openFile('contracts/1_Storage.sol') |
||||||
|
.waitForElementVisible('*[id="editorView"]', 10000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('function retrieve() public view returns (uint256){')) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Should install slither #group6': function (browser: NightwatchBrowser) { |
||||||
|
browser.perform(async (done) => { |
||||||
|
await installSlither() |
||||||
|
done() |
||||||
|
}) |
||||||
|
}, |
||||||
|
'run slither': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('[data-id="verticalIconsKindpluginManager"]') |
||||||
|
.scrollAndClick('[data-id="pluginManagerComponentActivateButtonsolidityStaticAnalysis"]') |
||||||
|
.clickLaunchIcon('solidity').click('*[data-id="compilerContainerCompileBtn"]') |
||||||
|
.pause(1000) |
||||||
|
.clickLaunchIcon('solidityStaticAnalysis') |
||||||
|
.useXpath() |
||||||
|
.click('//*[@id="staticAnalysisRunBtn"]') |
||||||
|
.waitForElementPresent('//*[@id="staticanalysisresult"]', 5000) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-id='nolibslitherwarnings'][contains(text(), '1')]", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
timeout: 5000 |
||||||
|
}) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//div[@data-id='block']/span[contains(text(), '1 warnings found.')]", |
||||||
|
locateStrategy: 'xpath', |
||||||
|
timeout: 5000 |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
after: function (browser: NightwatchBrowser) { |
||||||
|
browser.end() |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
async function installSlither(): Promise<void> { |
||||||
|
console.log('installSlither', process.cwd()) |
||||||
|
try { |
||||||
|
try { |
||||||
|
const solcVersion = '0.8.15' |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: requires Python3.6+ (pip3) to be installed on your system`) |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: solc-select will be installed along with Slither to set different solc compiler versions.`) |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: checking pip3 availability ...`) |
||||||
|
const pip3OP = execSync('pip3 --version') |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: pip3 found: ${pip3OP.toString()}`) |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: installing slither...`) |
||||||
|
const slitherOP = execSync('pip3 install slither-analyzer') |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: slither installation output: ${slitherOP.toString()}`) |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: installing solc-select...`) |
||||||
|
const solcSelectOP = execSync('pip3 install solc-select') |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: solc-select installation output: ${solcSelectOP.toString()}`) |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: installing solc ${solcVersion}...`) |
||||||
|
const solcInstallOP = execSync(`solc-select install ${solcVersion}`) |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: solc installation output: ${solcInstallOP.toString()}`) |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: setting solc version to ${solcVersion}...`) |
||||||
|
const solcUseOP = execSync(`solc-select use ${solcVersion}`) |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: solc setting installation output: ${solcUseOP.toString()}`) |
||||||
|
console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: Slither is ready to use!`) |
||||||
|
} catch (err) { |
||||||
|
console.log('\x1b[31m%s\x1b[0m', `[Slither Installation]: Error occurred: ${err}`) |
||||||
|
} |
||||||
|
} catch (e) { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
...process.platform.startsWith('linux')?tests:{} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
'open default template': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) |
||||||
|
.waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.click('button[data-id="landingPageImportFromTemplate"]') |
||||||
|
.waitForElementPresent('*[data-id="create-remixDefault"]') |
||||||
|
.scrollAndClick('*[data-id="create-remixDefault"]') |
||||||
|
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') |
||||||
|
.waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') |
||||||
|
.pause(3000) |
||||||
|
.windowHandles(function (result) { |
||||||
|
console.log(result.value) |
||||||
|
browser.switchWindow(result.value[1]) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
.click('*[data-id="treeViewLitreeViewItemtests"]') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]') |
||||||
|
.click('*[data-id="treeViewLitreeViewItemcontracts"]') |
||||||
|
.waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]') |
||||||
|
.openFile('contracts/1_Storage.sol') |
||||||
|
.waitForElementVisible('*[id="editorView"]', 10000) |
||||||
|
.getEditorValue((content) => { |
||||||
|
browser.assert.ok(content.includes('function retrieve() public view returns (uint256){')) |
||||||
|
}) |
||||||
|
}) |
||||||
|
.end() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,246 @@ |
|||||||
|
import {NightwatchBrowser} from 'nightwatch' |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
open: function (browser: NightwatchBrowser) { |
||||||
|
browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') |
||||||
|
}, |
||||||
|
'open xterm linux and create a file': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="tabXTerm"]', 10000) |
||||||
|
.click('*[data-id="tabXTerm"]') |
||||||
|
.waitForElementVisible('*[data-type="remixUIXT"]', 10000) |
||||||
|
.click('*[data-type="remixUIXT"]') |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('echo test > example.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemexample.txt"]', 10000) |
||||||
|
}, |
||||||
|
'rename that file': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('mv example.txt newExample.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample.txt"]', 10000) |
||||||
|
}, |
||||||
|
'create a file and delete it': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('touch newExample2.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('rm newExample2.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) |
||||||
|
}, |
||||||
|
'run a git clone command': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('git clone https://github.com/ethereum/awesome-remix').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) |
||||||
|
.click('*[data-id="treeViewLitreeViewItemawesome-remix"]') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix/README.md"]', 10000) |
||||||
|
}, |
||||||
|
'remove the cloned repo': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-type="remixUIXT"]', 10000) |
||||||
|
.click('*[data-type="remixUIXT"]') |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('rm -rf awesome-remix').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) |
||||||
|
}, |
||||||
|
'list files': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(2000) |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('ls').sendKeys(this.Keys.ENTER) |
||||||
|
}).pause(3000) |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok((result.value as string).includes('newExample.txt')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'switch to a new terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="createTerminalButton"]', 10000) |
||||||
|
.click('*[data-id="createTerminalButton"]') |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.assert.ok((result.value as any).length === 2) |
||||||
|
}) |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok(!(result.value as string).includes('newExample.txt')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'switch to a third terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="createTerminalButton"]', 10000) |
||||||
|
.click('*[data-id="createTerminalButton"]') |
||||||
|
.waitForElementVisible( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
10000 |
||||||
|
) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.assert.ok((result.value as any).length === 3) |
||||||
|
}) |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('echo thirdterminal').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'switch back to the second terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.elementIdClick(Object.values((result.value as any)[1])[0] as any) |
||||||
|
}) |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok(!(result.value as string).includes('newExample.txt')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'close the second terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="closeTerminalButton"]', 10000) |
||||||
|
.click('*[data-id="closeTerminalButton"]') |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.assert.ok((result.value as any).length === 2) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'switch back to the first terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.elementIdClick(Object.values((result.value as any)[0])[0] as any) |
||||||
|
}) |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok((result.value as string).includes('newExample.txt')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'switch to the output panel': function (browser: NightwatchBrowser) { |
||||||
|
browser.waitForElementVisible('*[data-id="tabOutput"]', 10000).click('*[data-id="tabOutput"]').waitForElementNotPresent('*[data-id="createTerminalButton"]', 10000) |
||||||
|
}, |
||||||
|
'switch back to xterminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="tabXTerm"]', 10000) |
||||||
|
.click('*[data-id="tabXTerm"]') |
||||||
|
.waitForElementVisible('*[data-type="remixUIXT"]', 10000) |
||||||
|
.click('*[data-type="remixUIXT"]') |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok((result.value as string).includes('newExample.txt')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'clear the terminal and type exit': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(1000) |
||||||
|
.waitForElementVisible('*[data-id="clearTerminalButton"]', 10000) |
||||||
|
.click('*[data-id="clearTerminalButton"]') |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok(!(result.value as string).includes('newExample.txt')) |
||||||
|
.waitForElementVisible( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
10000 |
||||||
|
) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('exit').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.pause(1000) |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.assert.ok((result.value as any).length === 1) |
||||||
|
}).end() |
||||||
|
} |
||||||
|
).pause(3000) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
...process.platform.startsWith('win')?{}:tests |
||||||
|
} |
@ -0,0 +1,249 @@ |
|||||||
|
import {NightwatchBrowser} from 'nightwatch' |
||||||
|
|
||||||
|
const tests = { |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
done() |
||||||
|
}, |
||||||
|
open: function (browser: NightwatchBrowser) { |
||||||
|
browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') |
||||||
|
}, |
||||||
|
'open xterm window and create a file': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="tabXTerm"]', 10000) |
||||||
|
.click('*[data-id="tabXTerm"]') |
||||||
|
.waitForElementVisible('*[data-id="select_shell"]') |
||||||
|
.click('*[data-id="select_shell"]') |
||||||
|
.waitForElementVisible('*[data-id="select_powershell.exe"]') |
||||||
|
.click('*[data-id="select_powershell.exe"]') |
||||||
|
.pause(3000) |
||||||
|
.waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) |
||||||
|
.click("[data-active='1'][data-type='remixUIXT']") |
||||||
|
.pause(1000) |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('"test" | Out-File -FilePath example.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemexample.txt"]', 10000) |
||||||
|
}, |
||||||
|
'rename that file': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('Move-Item -Path example.txt -Destination newExample.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample.txt"]', 10000) |
||||||
|
}, |
||||||
|
'create a file and delete it': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('touch newExample2.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('Remove-Item -Path newExample2.txt').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) |
||||||
|
}, |
||||||
|
'run a git clone command': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('git clone https://github.com/ethereum/awesome-remix').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) |
||||||
|
.click('*[data-id="treeViewLitreeViewItemawesome-remix"]') |
||||||
|
.waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix/README.md"]', 10000) |
||||||
|
}, |
||||||
|
'remove the cloned repo': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) |
||||||
|
.click("[data-active='1'][data-type='remixUIXT']") |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('Remove-Item -Path awesome-remix -Recurse -Force').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) |
||||||
|
}, |
||||||
|
'list files': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.pause(3000) |
||||||
|
.waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) |
||||||
|
.click("[data-active='1'][data-type='remixUIXT']") |
||||||
|
.saveScreenshot('./reports/screenshots/list-files.png') |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('ls').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
.saveScreenshot('./reports/screenshots/list-files-after.png') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.pause(2000) |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok((result.value as string).includes('newExample')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'switch to a new terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="select_shell"]') |
||||||
|
.click('*[data-id="select_shell"]') |
||||||
|
.waitForElementVisible('*[data-id="select_powershell.exe"]') |
||||||
|
.click('*[data-id="select_powershell.exe"]') |
||||||
|
.pause(3000) |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
console.log(result) |
||||||
|
browser.assert.ok((result.value as any).length === 3) |
||||||
|
}) |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok(!(result.value as string).includes('newExample')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'switch to a third terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="select_shell"]') |
||||||
|
.click('*[data-id="select_shell"]') |
||||||
|
.waitForElementVisible('*[data-id="select_powershell.exe"]') |
||||||
|
.click('*[data-id="select_powershell.exe"]') |
||||||
|
.pause(3000) |
||||||
|
.waitForElementVisible( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
10000 |
||||||
|
) |
||||||
|
.click({ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}) |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.assert.ok((result.value as any).length === 4) |
||||||
|
}) |
||||||
|
.perform(function () { |
||||||
|
const actions = this.actions({async: true}) |
||||||
|
return actions.sendKeys('echo thirdterminal').sendKeys(this.Keys.ENTER) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'switch back to the second terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.elementIdClick(Object.values((result.value as any)[2])[0] as any) |
||||||
|
}) |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok(!(result.value as string).includes('newExample')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'close the second terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="closeTerminalButton"]', 10000) |
||||||
|
.click('*[data-id="closeTerminalButton"]') |
||||||
|
.pause(1000) |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.assert.ok((result.value as any).length === 3) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'switch back to the first terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.elementIdClick(Object.values((result.value as any)[1])[0] as any) |
||||||
|
}) |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok((result.value as string).includes('newExample')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'switch to the output panel': function (browser: NightwatchBrowser) { |
||||||
|
browser.waitForElementVisible('*[data-id="tabOutput"]', 10000).click('*[data-id="tabOutput"]').waitForElementNotPresent('*[data-id="createTerminalButton"]', 10000) |
||||||
|
}, |
||||||
|
'switch back to xterminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="tabXTerm"]', 10000) |
||||||
|
.click('*[data-id="tabXTerm"]') |
||||||
|
.waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) |
||||||
|
.click("[data-active='1'][data-type='remixUIXT']") |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok((result.value as string).includes('newExample')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'clear the terminal': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="clearTerminalButton"]', 10000) |
||||||
|
.click('*[data-id="clearTerminalButton"]') |
||||||
|
.getText( |
||||||
|
{ |
||||||
|
selector: "//*[@data-type='remixUIXT' and @data-active='1']", |
||||||
|
timeout: 10000, |
||||||
|
locateStrategy: 'xpath', |
||||||
|
}, |
||||||
|
function (result) { |
||||||
|
console.log('Text content of the element:', result.value) |
||||||
|
browser.assert.ok(!(result.value as string).includes('newExample')) |
||||||
|
} |
||||||
|
) |
||||||
|
}, |
||||||
|
'close all terminals': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementVisible('*[data-id="closeTerminalButton"]', 10000) |
||||||
|
.click('*[data-id="closeTerminalButton"]') |
||||||
|
.pause(3000) |
||||||
|
.click('*[data-id="closeTerminalButton"]') |
||||||
|
.pause(3000) |
||||||
|
.click('*[data-id="closeTerminalButton"]') |
||||||
|
.pause(3000) |
||||||
|
.elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { |
||||||
|
browser.assert.ok((result.value as any).length === 0) |
||||||
|
}).end() |
||||||
|
}, |
||||||
|
after: function (browser: NightwatchBrowser) { |
||||||
|
browser.end() |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
...process.platform.startsWith('win')?tests:{} |
||||||
|
} |
@ -0,0 +1,108 @@ |
|||||||
|
// Merge custom command types with nightwatch types
|
||||||
|
/* eslint-disable no-use-before-define */ |
||||||
|
import {NightwatchBrowser} from 'nightwatch' // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||||
|
export type callbackCheckVerifyCallReturnValue = (values: string[]) => {message: string; pass: boolean} |
||||||
|
|
||||||
|
declare module 'nightwatch' { |
||||||
|
export interface NightwatchCustomCommands { |
||||||
|
clickLaunchIcon(icon: string): NightwatchBrowser |
||||||
|
switchBrowserTab(index: number): NightwatchBrowser |
||||||
|
scrollAndClick(target: string): NightwatchBrowser |
||||||
|
scrollInto(target: string): NightwatchBrowser |
||||||
|
testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser |
||||||
|
setEditorValue(value: string, callback?: () => void): NightwatchBrowser |
||||||
|
addFile(name: string, content: NightwatchContractContent, readMeFile?: string): NightwatchBrowser |
||||||
|
verifyContracts(compiledContractNames: string[], opts?: {wait: number; version?: string; runs?: string}): NightwatchBrowser |
||||||
|
selectAccount(account?: string): NightwatchBrowser |
||||||
|
clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser |
||||||
|
testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser |
||||||
|
goToVMTraceStep(step: number, incr?: number): NightwatchBrowser |
||||||
|
checkVariableDebug(id: string, debugValue: NightwatchCheckVariableDebugValue): NightwatchBrowser |
||||||
|
addAtAddressInstance(address: string, isValidFormat: boolean, isValidChecksum: boolean, isAbi?: boolean): NightwatchBrowser |
||||||
|
modalFooterOKClick(id?: string): NightwatchBrowser |
||||||
|
clickInstance(index: number): NightwatchBrowser |
||||||
|
journalLastChildIncludes(val: string): NightwatchBrowser |
||||||
|
executeScriptInTerminal(script: string): NightwatchBrowser |
||||||
|
clearEditableContent(cssSelector: string): NightwatchBrowser |
||||||
|
journalChildIncludes(val: string, opts = {shouldHaveOnlyOneOccurence: boolean}): NightwatchBrowser |
||||||
|
debugTransaction(index: number): NightwatchBrowser |
||||||
|
checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser |
||||||
|
openFile(name: string): NightwatchBrowser |
||||||
|
refreshPage(): NightwatchBrowser |
||||||
|
verifyLoad(): NightwatchBrowser |
||||||
|
renamePath(path: string, newFileName: string, renamedPath: string): NightwatchBrowser |
||||||
|
rightClickCustom(cssSelector: string): NightwatchBrowser |
||||||
|
scrollToLine(line: number): NightwatchBrowser |
||||||
|
waitForElementContainsText(id: string, value: string, timeout?: number): NightwatchBrowser |
||||||
|
getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser |
||||||
|
modalFooterCancelClick(id?: string): NightwatchBrowser |
||||||
|
selectContract(contractName: string): NightwatchBrowser |
||||||
|
createContract(inputParams: string): NightwatchBrowser |
||||||
|
getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser |
||||||
|
testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser |
||||||
|
getEditorValue(callback: (content: string) => void): NightwatchBrowser |
||||||
|
getInstalledPlugins(cb: (plugins: string[]) => void): NightwatchBrowser |
||||||
|
verifyCallReturnValue(address: string, checks: string[] | callbackCheckVerifyCallReturnValue): NightwatchBrowser |
||||||
|
testEditorValue(testvalue: string): NightwatchBrowser |
||||||
|
removeFile(path: string, workspace: string): NightwatchBrowser |
||||||
|
switchBrowserWindow(url: string, windowName: string, cb: (browser: NightwatchBrowser, window?: NightwatchCallbackResult<Window>) => void): NightwatchBrowser |
||||||
|
setupMetamask(passphrase: string, password: string): NightwatchBrowser |
||||||
|
signMessage(msg: string, callback: (hash: {value: string}, signature: {value: string}) => void): NightwatchBrowser |
||||||
|
setSolidityCompilerVersion(version: string): NightwatchBrowser |
||||||
|
clickElementAtPosition(cssSelector: string, index: number, opt?: {forceSelectIfUnselected: boolean}): NightwatchBrowser |
||||||
|
notContainsText(cssSelector: string, text: string): NightwatchBrowser |
||||||
|
sendLowLevelTx(address: string, value: string, callData: string): NightwatchBrowser |
||||||
|
journalLastChild(val: string): NightwatchBrowser |
||||||
|
checkTerminalFilter(filter: string, test: string): NightwatchBrowser |
||||||
|
noWorkerErrorFor(version: string): NightwatchBrowser |
||||||
|
validateValueInput(selector: string, valueTosSet: string[], expectedValue: string): NightwatchBrowser |
||||||
|
checkAnnotations(type: string): NightwatchBrowser |
||||||
|
checkAnnotationsNotPresent(type: string): NightwatchBrowser |
||||||
|
getLastTransactionHash(callback: (hash: string) => void) |
||||||
|
currentWorkspaceIs(name: string): NightwatchBrowser |
||||||
|
addLocalPlugin(this: NightwatchBrowser, profile: Profile & LocationProfile & ExternalProfile): NightwatchBrowser |
||||||
|
acceptAndRemember(this: NightwatchBrowser, remember: boolean, accept: boolean): NightwatchBrowser |
||||||
|
clearConsole(this: NightwatchBrowser): NightwatchBrowser |
||||||
|
clearTransactions(this: NightwatchBrowser): NightwatchBrowser |
||||||
|
getBrowserLogs(this: NightwatchBrowser): NightwatchBrowser |
||||||
|
currentSelectedFileIs(name: string): NightwatchBrowser |
||||||
|
switchWorkspace: (workspaceName: string) => NightwatchBrowser |
||||||
|
switchEnvironment: (provider: string) => NightwatchBrowser |
||||||
|
connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser |
||||||
|
waitForElementNotContainsText: (id: string, value: string, timeout: number = 10000) => NightwatchBrowser |
||||||
|
hideToolTips: (this: NightwatchBrowser) => NightwatchBrowser |
||||||
|
enableClipBoard: () => NightwatchBrowser |
||||||
|
} |
||||||
|
|
||||||
|
export interface NightwatchBrowser { |
||||||
|
api: this |
||||||
|
emit: (status: string) => void |
||||||
|
fullscreenWindow: (result?: any) => this |
||||||
|
keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void): NightwatchBrowser |
||||||
|
sendKeys: (selector: string, inputValue: string | string[], callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void) => NightwatchBrowser |
||||||
|
} |
||||||
|
|
||||||
|
export interface NightwatchAPI { |
||||||
|
keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void): NightwatchAPI |
||||||
|
} |
||||||
|
|
||||||
|
export interface NightwatchContractContent { |
||||||
|
content: string |
||||||
|
} |
||||||
|
|
||||||
|
export interface NightwatchClickFunctionExpectedInput { |
||||||
|
types: string |
||||||
|
values: string |
||||||
|
} |
||||||
|
|
||||||
|
export interface NightwatchTestFunctionExpectedInput { |
||||||
|
[key: string]: any |
||||||
|
} |
||||||
|
|
||||||
|
export interface NightwatchTestConstantFunctionExpectedInput { |
||||||
|
types: string |
||||||
|
values: string |
||||||
|
} |
||||||
|
|
||||||
|
export type NightwatchCheckVariableDebugValue = NightwatchTestFunctionExpectedInput |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
{ |
||||||
|
"extends": "./tsconfig.json", |
||||||
|
"compilerOptions": { |
||||||
|
"outDir": "build-e2e", |
||||||
|
"target": "ES6" |
||||||
|
}, |
||||||
|
"include": ["test/**/*.ts", "test/**/*.js", "../remix-ide-e2e/src/commands"] |
||||||
|
} |
@ -1,17 +1,35 @@ |
|||||||
{ |
{ |
||||||
"compilerOptions": { |
"compilerOptions": { |
||||||
"target": "es6", |
"target": "ES2018", |
||||||
"module": "commonjs", |
"allowJs": true, |
||||||
|
"module": "CommonJS", |
||||||
"skipLibCheck": true, |
"skipLibCheck": true, |
||||||
"esModuleInterop": true, |
"esModuleInterop": true, |
||||||
"noImplicitAny": true, |
"noImplicitAny": false, |
||||||
"allowSyntheticDefaultImports": true, |
|
||||||
"sourceMap": true, |
"sourceMap": true, |
||||||
"strictPropertyInitialization": false, |
"baseUrl": ".", |
||||||
"strict": true, |
"outDir": "./build", |
||||||
"outDir": "build", |
"moduleResolution": "node", |
||||||
"rootDir": "./src/", |
"resolveJsonModule": true, |
||||||
"noEmitOnError": true, |
"paths": { |
||||||
"typeRoots": ["node_modules/@types", "./types"] |
"*": [ |
||||||
} |
"node_modules/*" |
||||||
|
], |
||||||
|
"@remix-api": [ |
||||||
|
"../../libs/remix-api/src/lib/types/git.ts" |
||||||
|
], |
||||||
|
"@remix-git": [ |
||||||
|
"../../libs/remix-git/" |
||||||
|
], |
||||||
|
}, |
||||||
|
"typeRoots": [ |
||||||
|
"src/**/*.d.ts", |
||||||
|
"node_modules/@types", |
||||||
|
"test/**/*.d.ts", |
||||||
|
"../remix-ide-e2e/src/**/*.d.ts" |
||||||
|
] |
||||||
|
}, |
||||||
|
"include": [ |
||||||
|
"src/**/*", |
||||||
|
] |
||||||
} |
} |
@ -0,0 +1,44 @@ |
|||||||
|
const path = require('path'); |
||||||
|
const nodeExternals = require('webpack-node-externals'); |
||||||
|
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); |
||||||
|
const mode = process.env.NODE_ENV || 'development'; |
||||||
|
const webpack = require('webpack'); |
||||||
|
module.exports = { |
||||||
|
mode, |
||||||
|
entry: { |
||||||
|
main: './src/main.ts', |
||||||
|
preload: './src/preload.ts', |
||||||
|
}, |
||||||
|
target: 'electron-main', |
||||||
|
externals: [nodeExternals()], |
||||||
|
module: { |
||||||
|
rules: [ |
||||||
|
{ |
||||||
|
test: /\.ts$/, |
||||||
|
include: /src/, |
||||||
|
use: [{ loader: 'ts-loader' }] |
||||||
|
}, |
||||||
|
{ |
||||||
|
test: /\.node$/, |
||||||
|
use: 'node-loader' |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
resolve: { |
||||||
|
extensions: ['.ts', '.js'], |
||||||
|
plugins: [new TsconfigPathsPlugin({ configFile: './tsconfig.json' })] |
||||||
|
}, |
||||||
|
plugins: [ |
||||||
|
new webpack.DefinePlugin({ |
||||||
|
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || mode) |
||||||
|
}) |
||||||
|
], |
||||||
|
output: { |
||||||
|
path: path.resolve(__dirname, 'build'), |
||||||
|
filename: '[name].js' |
||||||
|
}, |
||||||
|
node: { |
||||||
|
__dirname: false, |
||||||
|
__filename: false |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -1 +1,2 @@ |
|||||||
export * from './lib/remix-api' |
export * from './lib/remix-api' |
||||||
|
export * from './lib/types/git' |
@ -1,10 +1,13 @@ |
|||||||
import { commitChange } from "@remix-ui/git"; |
import { commitChange } from "@remix-api"; |
||||||
import { IFileSystem } from "@remixproject/plugin-api" |
import { IFileSystem } from "@remixproject/plugin-api" |
||||||
|
|
||||||
// Extended interface with 'diff' method
|
// Extended interface with 'diff' method
|
||||||
export interface IExtendedFileSystem extends IFileSystem { |
export interface IExtendedFileSystem extends IFileSystem { |
||||||
methods: IFileSystem['methods'] & { |
methods: IFileSystem['methods'] & { |
||||||
|
/** Compare the differences between two files */ |
||||||
diff(change: commitChange): Promise<void> |
diff(change: commitChange): Promise<void> |
||||||
|
refresh(): Promise<void> |
||||||
|
hasGitSubmodules(): Promise<boolean> |
||||||
isGitRepo(): Promise<boolean> |
isGitRepo(): Promise<boolean> |
||||||
}; |
}; |
||||||
} |
} |
@ -0,0 +1,13 @@ |
|||||||
|
import { StatusEvents } from "@remixproject/plugin-utils"; |
||||||
|
|
||||||
|
export interface IFs { |
||||||
|
events: { |
||||||
|
workingDirChanged(path: string): Promise<void>, |
||||||
|
} & StatusEvents, |
||||||
|
methods: { |
||||||
|
selectFolder(path?: string, title?: string, button?: string): Promise<string>
|
||||||
|
openWindow(path?: string): Promise<void>, |
||||||
|
getWorkingDir(): Promise<string>, |
||||||
|
openFolderInSameWindow(path: string): Promise<void>, |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
import { StatusEvents } from "@remixproject/plugin-utils" |
||||||
|
import { ReadBlobResult, ReadCommitResult, StatusRow } from "isomorphic-git" |
||||||
|
import { commitChange, repositoriesInput, repository, cloneInputType, branchesInputType, branch, remote, logInputType, remoteCommitsInputType, pagedCommits, fetchInputType, pullInputType, pushInputType, currentBranchInput, branchInputType, checkoutInputType, addInputType, rmInputType, resolveRefInput, readBlobInput, commitInputType, statusInput, compareBranchesInput, branchDifference, initInputType, updateSubmodulesInput } from "../types/git" |
||||||
|
|
||||||
|
export interface IGitApi { |
||||||
|
events: { |
||||||
|
"checkout": () => void |
||||||
|
"clone": () => void |
||||||
|
"add": () => void |
||||||
|
"rm": () => void |
||||||
|
"commit": () => void |
||||||
|
"branch": () => void |
||||||
|
"init": () => void |
||||||
|
} & StatusEvents, |
||||||
|
methods: { |
||||||
|
getCommitChanges(oid1: string, oid2: string): Promise<commitChange[]> |
||||||
|
repositories(input: repositoriesInput): Promise<repository[]> |
||||||
|
clone(input: cloneInputType): Promise<any> |
||||||
|
branches(input?: branchesInputType): Promise<branch[]>, |
||||||
|
remotes(): Promise<remote[]>, |
||||||
|
log(input: logInputType): Promise<ReadCommitResult[]>, |
||||||
|
remotecommits(input: remoteCommitsInputType): Promise<pagedCommits[]> |
||||||
|
fetch(input: fetchInputType): Promise<any> |
||||||
|
pull(input: pullInputType): Promise<any> |
||||||
|
push(input: pushInputType): Promise<any> |
||||||
|
currentbranch(input?: currentBranchInput): Promise<branch> |
||||||
|
branch(input: branchInputType): Promise<void> |
||||||
|
checkout(input: checkoutInputType): Promise<void> |
||||||
|
add(input: addInputType): Promise<void> |
||||||
|
rm(input: rmInputType): Promise<void> |
||||||
|
resolveref(input: resolveRefInput): Promise<string> |
||||||
|
readblob(input: readBlobInput): Promise<ReadBlobResult> |
||||||
|
commit(input: commitInputType): Promise<string> |
||||||
|
addremote(input: remote): Promise<void> |
||||||
|
delremote(input: remote): Promise<void> |
||||||
|
status(input?: statusInput): Promise<Array<StatusRow>> |
||||||
|
compareBranches(input: compareBranchesInput): Promise<branchDifference> |
||||||
|
init(input?: initInputType): Promise<void> |
||||||
|
updateSubmodules: (input: updateSubmodulesInput) => Promise<void> |
||||||
|
version: () => Promise<string> |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,10 @@ |
|||||||
|
import { ITerminal } from "@remixproject/plugin-api/src/lib/terminal" |
||||||
|
import { StatusEvents } from "@remixproject/plugin-utils" |
||||||
|
|
||||||
|
export interface IExtendedTerminalApi extends ITerminal { |
||||||
|
events: { |
||||||
|
} & StatusEvents |
||||||
|
methods: ITerminal['methods'] & { |
||||||
|
logHtml(html: string): void |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,206 @@ |
|||||||
|
import { Endpoints } from "@octokit/types" |
||||||
|
import { AuthCallback, HttpClient, ReadCommitResult } from "isomorphic-git" |
||||||
|
|
||||||
|
export type branchDifference = { |
||||||
|
uniqueHeadCommits: ReadCommitResult[], |
||||||
|
uniqueRemoteCommits: ReadCommitResult[], |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
export type commitChange = { |
||||||
|
type: commitChangeType |
||||||
|
path: string, |
||||||
|
hashModified: string, |
||||||
|
hashOriginal: string, |
||||||
|
original?: string, |
||||||
|
modified?: string, |
||||||
|
readonly?: boolean |
||||||
|
} |
||||||
|
|
||||||
|
export type commitChangeTypes = { |
||||||
|
"deleted": "D" |
||||||
|
"modified": "M" |
||||||
|
"added": "A", |
||||||
|
"unknown": "?" |
||||||
|
} |
||||||
|
|
||||||
|
export type pagedCommits = { |
||||||
|
page: number, |
||||||
|
perPage: number, |
||||||
|
total: number, |
||||||
|
hasNextPage: boolean, |
||||||
|
commits: ReadCommitResult[] |
||||||
|
} |
||||||
|
|
||||||
|
export enum syncStatus { |
||||||
|
"sync" = "sync", |
||||||
|
"publishBranch" = "publishBranch", |
||||||
|
"none" = "none", |
||||||
|
} |
||||||
|
|
||||||
|
export type repository = { |
||||||
|
name: string |
||||||
|
html_url: string |
||||||
|
owner: { |
||||||
|
login: string |
||||||
|
}, |
||||||
|
full_name: string |
||||||
|
default_branch: string |
||||||
|
id: number |
||||||
|
url: string |
||||||
|
} |
||||||
|
|
||||||
|
export type branch = { |
||||||
|
name: string |
||||||
|
remote: remote |
||||||
|
} |
||||||
|
|
||||||
|
export type remote = { |
||||||
|
name: string |
||||||
|
url: string |
||||||
|
} |
||||||
|
|
||||||
|
export type remoteBranch = { |
||||||
|
name: string |
||||||
|
} |
||||||
|
|
||||||
|
export type commitChangeType = keyof commitChangeTypes |
||||||
|
|
||||||
|
export type initInputType = { |
||||||
|
defaultBranch: string |
||||||
|
} |
||||||
|
|
||||||
|
export type author = { |
||||||
|
name: string, |
||||||
|
email: string, |
||||||
|
} |
||||||
|
|
||||||
|
export type updateSubmodulesInput = { |
||||||
|
dir?: string |
||||||
|
token?: string |
||||||
|
} |
||||||
|
|
||||||
|
export type remoteCommitsInputType = { |
||||||
|
owner: string, repo: string, token: string, branch: string, length: number, page: number |
||||||
|
} |
||||||
|
|
||||||
|
export type compareBranchesInput = { |
||||||
|
branch: branch, remote: remote |
||||||
|
} |
||||||
|
|
||||||
|
export type fetchInputType = { |
||||||
|
remote: remote, |
||||||
|
ref?: branch, |
||||||
|
remoteRef?: branch, |
||||||
|
depth?: number, |
||||||
|
singleBranch?: boolean, |
||||||
|
relative?: boolean, |
||||||
|
quiet?: boolean |
||||||
|
author?: author |
||||||
|
token?: string |
||||||
|
} |
||||||
|
|
||||||
|
export type logInputType = { |
||||||
|
ref: string, |
||||||
|
depth?: number, |
||||||
|
} |
||||||
|
|
||||||
|
export type pullInputType = { |
||||||
|
remote: remote,
|
||||||
|
ref: branch,
|
||||||
|
remoteRef?: branch |
||||||
|
author?: author |
||||||
|
token?: string |
||||||
|
} |
||||||
|
|
||||||
|
export type pushInputType = { |
||||||
|
remote: remote,
|
||||||
|
ref: branch,
|
||||||
|
remoteRef?: branch,
|
||||||
|
force?: boolean, |
||||||
|
author?: author, |
||||||
|
token?: string |
||||||
|
} |
||||||
|
|
||||||
|
export type branchInputType = { |
||||||
|
ref: string, |
||||||
|
checkout?: boolean |
||||||
|
refresh?: boolean |
||||||
|
force?: boolean |
||||||
|
} |
||||||
|
|
||||||
|
export type currentBranchInput = { |
||||||
|
fs: any, |
||||||
|
dir: string |
||||||
|
} |
||||||
|
|
||||||
|
export type checkoutInputType = { |
||||||
|
ref: string, |
||||||
|
force?: boolean, |
||||||
|
remote?: string |
||||||
|
refresh?: boolean |
||||||
|
fetch?: boolean |
||||||
|
} |
||||||
|
|
||||||
|
export type addInputType = { |
||||||
|
filepath: string | string[] |
||||||
|
} |
||||||
|
|
||||||
|
export type rmInputType = { |
||||||
|
filepath: string |
||||||
|
} |
||||||
|
|
||||||
|
export type resolveRefInput = { |
||||||
|
ref: string |
||||||
|
} |
||||||
|
|
||||||
|
export type readBlobInput = { |
||||||
|
oid: string, |
||||||
|
filepath: string |
||||||
|
} |
||||||
|
|
||||||
|
export type commitInputType = { |
||||||
|
author: { |
||||||
|
name: string, |
||||||
|
email: string, |
||||||
|
}, |
||||||
|
message: string, |
||||||
|
} |
||||||
|
|
||||||
|
export type branchesInputType = { |
||||||
|
fs?: any |
||||||
|
dir?: string |
||||||
|
} |
||||||
|
|
||||||
|
export interface cloneInputType { |
||||||
|
url: string, |
||||||
|
branch?: string, |
||||||
|
depth?: number, |
||||||
|
singleBranch?: boolean |
||||||
|
workspaceName?: string |
||||||
|
workspaceExists?: boolean |
||||||
|
token?: string |
||||||
|
dir?: string // where the clone should happen on desktop
|
||||||
|
} |
||||||
|
|
||||||
|
export interface repositoriesInput { token: string, page?: number, per_page?: number } |
||||||
|
|
||||||
|
export interface statusInput { ref: string, filepaths?: string[] } |
||||||
|
|
||||||
|
export type isoGitFSConfig = { |
||||||
|
fs: any, |
||||||
|
dir: string, |
||||||
|
} |
||||||
|
|
||||||
|
export type isoGitProxyConfig = { |
||||||
|
corsProxy: string |
||||||
|
http: HttpClient |
||||||
|
onAuth: AuthCallback |
||||||
|
} |
||||||
|
|
||||||
|
export type GitHubUser = Partial<Endpoints["GET /user"]["response"]['data']> & { |
||||||
|
isConnected: boolean |
||||||
|
} |
||||||
|
|
||||||
|
export type userEmails = Endpoints["GET /user/emails"]["response"]["data"] |
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue