Best JavaScript code snippet using playwright-internal
api.js
Source:api.js  
1const path = require('path');2const fs = require('fs');3const fsp = fs.promises;4const debug = require('debug')('dogi:app:api');5const glob = require("glob");6const docker = require('./docker')7const {openPromise, toInstanceId, validateFilename, getNamespace} = require('./util');8const simpleGit = require('simple-git');9const {flushStream} = require("./util");10const git = simpleGit();11const {processCallback} = require("./callbacks");12const {createOutputs} = require('./outputs');13const {getInternalSharedDir} = require('./common');14exports.build = async ({sshUrl, instanceId, dockerfile: _dockerfile, output}) => {15    const dockerfile = _dockerfile || 'Dockerfile';16    const instanceRepoDir = path.join(getInternalSharedDir(instanceId), 'repo');17    await git.clone(sshUrl, instanceRepoDir);18    let buildFiles = await fsp.readdir(instanceRepoDir);19    const buildStream = await docker.buildImage({20        context: instanceRepoDir,21        src: buildFiles22    }, {t: instanceId, dockerfile});23    buildStream.pipe(output);24    await new Promise((resolve, reject) => {25        docker.modem.followProgress(buildStream, (err, res) => err ? reject(err) : resolve(res));26    });27}28exports.run = async function({instanceId, bashc, cmd, mounts, env, output}) {29    const image = instanceId;30    let _cmd = null;31    if (cmd) {32        _cmd = cmd33    } else if (bashc) {34        _cmd = ['bash', '-c', bashc];35    }36    const envArr = [];37    if (env) {38        for (const kv of Object.entries(env)) {39            envArr.push(kv.join('='));40        }41    }42    let createOptions = {43        'name': instanceId,44        'Hostname': '',45        'User': '',46        'AttachStdin': false,47        'AttachStdout': true,48        'AttachStderr': true,49        'Tty': true,50        'OpenStdin': false,51        'StdinOnce': false,52        'Env': envArr,53        'Cmd': _cmd,54        'Image': image,55        'Volumes': {},56        'VolumesFrom': []57    };58    if (mounts) {59        const HostConfig = {60            Binds: mounts.map((mount) => `${mount.host}:${mount.container}`)61        };62        createOptions = {63            ...createOptions,64            HostConfig65        }66    }67    const containerCreated = openPromise();68    const containerFinished = openPromise();69    async function abort() {70        const container = await containerCreated;71        await silentKill(container);72    }73    async function start() {74        //cleanup possible dangling container from previous runs75        await silentKillByName(instanceId);76        const container = await docker.createContainer(createOptions);77        containerCreated.resolve(container);78        try {79            const stream = await container.attach({80                stream: true,81                stdout: true,82                stderr: true83            });84            stream.setEncoding('utf8');85            stream.pipe(output, {86                end: true87            });88            await container.start({});89            const result = await container.wait();90            containerFinished.resolve(result);91            return {result, container};92        } catch (e) {93            e.status = 500;94            throw e;95        } finally {96            await silentKill(container)97        }98    }99    start()100        .catch((e) => {101            containerCreated.reject(e);102            containerFinished.reject(e);103        });104    return {containerCreated, containerFinished, abort}105};106const instancesById = {};107exports.getRunningJobs = () => instancesById;108async function silentKill(container) {109    try {110        await container.remove({force: true});111    } catch (e) {112        debug('silently failed to remove container', e);113    }114}115async function silentKillByName(containerName) {116    let container = docker.getContainer(containerName);117    await silentKill(container);118}119/**120 * @typedef {Object} ContainerParams121 * @property {string} cmd122 * @property {string} bashc123 * @property {string} env124 * */125exports.lifecycle = async ({url, urlProto, explicitId, dockerfile, action, cmd, env, bashc, callbackUrl, containerFiles: containerFilesById, outputId}) => {126    let urlWithProto = url;127    if (urlProto !== 'ssh') {128        urlWithProto = `${urlProto}://${url}`;129    }130    if (outputId) {131        validateFilename(outputId);132    }133    let instanceId = toInstanceId({repoName: urlWithProto, explicitId});134    /** @type {DogiInstance} */135    const instance = instancesById[instanceId];136    if(!instance) {137        debug('no instance');138    }139    if (action === 'restart') {140        if (instance) {141            /*142                We want to keep only the most recent restart, because restart is the only way user can change call params,143                if this 'lock' would not be where, it would not be clear which restart won and the instance could have unexpected params144            */145            if(instance.pendingRestart) {146                instance.pendingRestart.reject('Killed by subsequent restart');147            }148            instance.pendingRestart = openPromise()149            await Promise.race([instance.abort(), instance.pendingRestart]);150        }151    }152    if (action === 'abort') {153        if (instance) {154            if(instance.pendingRestart) {155                instance.pendingRestart.reject('Killed by abort');156            }157            await instance.abort();158        }159        throw new Error('[abort] Instance not found');160    }161    const instanceDir = getInternalSharedDir(instanceId);162    if (action === 'peek') {163        const outputFilename = path.join(instanceDir, `dogi.out.${outputId}`);164        await fsp.access(outputFilename);165        /** @type {Outputs} */166        const outputs =  {167            outputFilesById: {168                [outputId]: outputFilename,169            }170        };171        return {outputs}172    }173    //catch all, we do not want to create duplicate instance174    //needs to be checked by id, could have been removed by restart175    if (instancesById[instanceId]) {176        return instance;177    }178    return withoutInstance();179    async function withoutInstance() {180        /**181         * @typedef {Object} DogiInstance182         * @property {string} instanceId - dogi_{namespace}_{repoHash}_{explicitIdHash} used for container, image and file naming183         * @property {string} explicitId - user provided id184         * @property {date} started185         * @property {Array.<string>} errors186         * @property {Promise.<any>} pendingRestart - this is never resolved, only rejected for subsequent restarts187         *                                            to ensure that only the most recent restart wins188         *                                            the idea is, that on successful restart instance object will be recreated189         *                                            and this set back to null190         * @property {Promise.<any>} runHandleCreated - resolved when container is started191         * @property {Promise.<any>} instanceFinished - resolved when instance is finished no matter if successful192         * @property {Promise.<any>} delayed - resolved when instance is finished, throws if error occurs193         * @property {boolean} isBeingDestroyed - set when abort is called194         * @property {Outputs} outputs195         * @property {CallbackResult} cb196         * @property {Object} env197         * @property {Function} abort - abort the instance by force removing the container198         * */199        /** @type {DogiInstance} */200        const newInstance = instancesById[instanceId] = {201            instanceId,202            explicitId,203            errors: [],204            started: Date.now(),205            url: urlWithProto,206            runHandleCreated: openPromise(),207            instanceFinished: openPromise(),208            isBeingDestroyed: false,209            delayed: null,210            env211        };212        await fsp.rmdir(instanceDir, {recursive: true});213        await fsp.mkdir(instanceDir, {recursive: true});214        newInstance.outputs = await createOutputs(instanceId, containerFilesById);215        newInstance.abort = async function() {216            if (newInstance.isBeingDestroyed) {217                return this.instanceFinished;218            }219            newInstance.errors.push('Killed by abort');220            newInstance.isBeingDestroyed = true;221            const runHandle = await this.runHandleCreated222            await runHandle.abort();223            await this.instanceFinished;224        }225        async function buildAndRun() {226            const logFilename = newInstance.outputs.outputFilesById['log'];227            const buildLog = fs.createWriteStream(logFilename);228            await exports.build({sshUrl: urlWithProto, dockerfile, instanceId, output: buildLog});229            // await flushStream(buildLog);230            const runLog = fs.createWriteStream(logFilename, {flags: 'a'});231            const runHandle = await exports.run({instanceId, mounts: newInstance.outputs.mounts, cmd, bashc, env, output: runLog});232            // await flushStream(runLog);233            newInstance.runHandleCreated.resolve(runHandle);234            const result = await runHandle.containerFinished;235            const {StatusCode} = result;236            if(StatusCode !== 0) {237                throw new Error(`Execution failed with code ${StatusCode}`);238            }239            if (callbackUrl) {240                const result = await processCallback(newInstance, callbackUrl);241                newInstance.cb = result;242                const {response: {status}} = result;243                const isSuccess = status >= 200 && status < 300;244                if (!isSuccess) {245                    throw new Error('Callback failed')246                }247            }248        }249        const delayed = buildAndRun();250        newInstance.delayed = delayed;251        delayed252            .catch(e => {253                newInstance.errors.push(e.message);254                console.error(e);255            })256            .finally(() => {257                delete instancesById[instanceId];258                newInstance.instanceFinished.resolve();259            })260        return newInstance;261    }262}263const {reverse, set} = require('lodash');264const {getOutputUrl} = require('./outputs');265/**266 *267 * @returns {Promise<Outputs>}268 */269exports.getOutputs = async () => {270    const baseDir = getInternalSharedDir();271    const files = await new Promise((res, rej) => {272        glob(path.join(baseDir, `dogi_${getNamespace()}_*/dogi.out.*`), (err, files) => {273            if (err) {274                return rej(err);275            }276            res(files);277        })278    });279    const byInstanceId = {};280    files.forEach(file => {281        const [filename, instanceId] = reverse(file.split('/'));282        const [outputId] = reverse(filename.split('.'));283        set(byInstanceId, [instanceId, 'outputs', outputId, 'url'], getOutputUrl({instanceId, outputId}));284    });285    /**286     * @typedef {Object} InstanceOutput287     * @property {String} id instance id288     * @property {{url: String}[]} outputs public urls of outputs289     */290    /**291     * @typedef {Object} Outputs292     * @property {InstanceOutput} outputs293     */294    const outputs = Object.keys(byInstanceId).map(id => ({id, ...byInstanceId[id]}))295    296    return {297        outputs298    }299};300exports.collectOutputs = async ({output, stream}) => {301    validateFilename(output);302    const baseDir = getInternalSharedDir();303    const files = await new Promise((res, rej) => {304        glob(path.join(baseDir, `dogi_${getNamespace()}_*/dogi.out.${output}`), (err, files) => {305            if (err) {306                return rej(err);307            }308            res(files);309        })310    })311    for (const fn of files) {312        await new Promise((res, rej) => {313            const rs = fs.createReadStream(fn);314            rs.pipe(stream, {end: false})315            rs.on('error', (e) => rej(e));316            rs.on('end', () => res());317        })318        stream.write('\n');319    }320    stream.end();...game.matter.js
Source:game.matter.js  
1import Player from "./player";2import Lightning from "./lightning";3export default class Game extends Phaser.Scene {4    constructor () {5        super({ key: "game" });6        this.player = null;7        this.score = 0;8        this.scoreText = null;9    }10    init (data) {11      this.name = data.name;12      this.number = data.number;13  }14    preload () {15    }16    create () {17      this.width = this.sys.game.config.width;18      this.height = this.sys.game.config.height;19      this.center_width = this.width / 2;20      this.center_height = this.height / 2;21      this.cameras.main.setBackgroundColor(0x210707);22      this.createMap();23      //this.addPlayer();24     // this.cameras.main.startFollow(this.player, true, 0.05, 0.05, 0, 100);25     // this.loadAudios(); 26     //  this.playMusic();27      this.addLightning();28    }29    addLightning() {30      this.lightningEffect = this.add.rectangle(0, 40, this.map.widthInPixels, this.map.heightInPixels, 0xffffff).setOrigin(0)31      this.lightningEffect.setAlpha(0);32      this.lightning = new Lightning(this)33    }34    addPlayer() {35      const { x, y } = {x: 100, y: 100}36      this.player = new Player(this, x, y);37      // Smoothly follow the player38      this.cameras.main.startFollow(this.player.sprite, false, 0.5, 0.5, 0, -300);39    }40    createMap() {41      // https://rexrainbow.github.io/phaser3-rex-notes/docs/site/tilemap/#map42      this.map = this.make.tilemap({ tileWidth: 32, tileHeight: 32, width: 300, height: 300});43      this.brickTiles = this.map.addTilesetImage('brick');44      this.layer1 = this.map.createBlankLayer('layer1', this.brickTiles);45      this.layer1.setCollision(20);46      // this.layer1.randomize(0, 0, this.map.width, this.map.height, [ -1, 0, 12 ]);47      this.finished = false;48      this.rooms = 0;49      const positions = [{x: 0, y: 0}];50      do {51        let {x, y} = positions[positions.length - 1];52        let position = this.createSquare(0, x, y, Phaser.Math.Between(5, 10), Phaser.Math.Between(5, 10));53        positions.push(position);54        this.rooms++;55      } while(this.rooms < 10)56      this.map.setCollisionBetween(0, 6); 57      this.map.setCollisionByProperty({ collides: true });58          // body will be accessible via tile.physics.matterBody.59      this.matter.world.convertTilemapLayer(this.layer1);60      this.matter.world.setBounds(0, 0, this.map.widthInPixels, this.map.heightInPixels);61      this.cameras.main.setBounds(0, 0, this.map.widthInPixels, this.map.heightInPixels);62      this.layer1.forEachTile(function (tile) {63        tile.label = "destroyable"64      });65      this.matter.world.on('collisionstart', function (event) {66        function getRootBody (body) {67          if (body.parent === body) return body; 68          while (body.parent !== body)69            body = body.parent;70          71          return body;72        }73        for (let i = 0; i < event.pairs.length; i++) {74            // The tile bodies in this example are a mixture of compound bodies and simple rectangle75            // bodies. The "label" property was set on the parent body, so we will first make sure76            // that we have the top level body instead of a part of a larger compound body.77            const bodyA = getRootBody(event.pairs[i].bodyA);78            const bodyB = getRootBody(event.pairs[i].bodyB);79            if ((bodyA.label === 'explosion' && bodyB.label === 'destroyable') ||80                (bodyB.label === 'explosion' && bodyA.label === 'destroyable'))81            {82                const ballBody = bodyA.label === 'explosion' ? bodyA : bodyB;83                const ball = ballBody.gameObject;84                const tileBody = bodyA.label === 'destroyable' ? bodyA : bodyB;85                const tile = tileBody.gameObject;86                // A body may collide with multiple other bodies in a step, so we'll use a flag to87                // only tween & destroy the ball once.88                if (tile.isBeingDestroyed) continue;89                90                tile.isBeingDestroyed = true;91                this.matter.world.remove(tileBody);92            }93        }94    }, this);95    }96    createSquare (tile, x, y, width, height) {97      Array(width).fill(0).forEach((_,i) => this.map.putTileAt(tile, x + i, y));98      Array(width).fill(0).forEach((_,i) => this.map.putTileAt(tile, x + i, y + height - 1));99      Array(height).fill(0).forEach((_,i) => this.map.putTileAt(tile, x, y + i));100      Array(height).fill(0).forEach((_,i) => this.map.putTileAt(tile, x + width - 1, y + i));101      const growinDirections = this.calculateGrowinOptions(x, y, width, height);102      const grow = Phaser.Math.RND.pick(growinDirections);103      return {104        "right": {x: x + width, y},105        "left": {x: x - width, y},106        "up": {x, y},107        "down": {x: x, y: y + height },108      }[grow.orientation];109    }110    calculateGrowinOptions(x, y, width, height) {111      const result = [];112      result.push({ orientation: "right", width: 7, height: 7 } );113      return result;114    }115    createMap2() {116      this.tileMap = this.make.tilemap({ key: "scene0" , tileWidth: 64, tileHeight: 64 });117      this.tileSetBg = this.tileMap.addTilesetImage("background");118      this.tileMap.createStaticLayer('background', this.tileSetBg)119  120      this.tileSet = this.tileMap.addTilesetImage("bricks");121      this.dangerousLayer = this.add.layer();122      this.platform = this.tileMap.createLayer('scene0', this.tileSet);123      this.deadly = this.tileMap.createLayer('deadly', this.tileSet);124      this.objectsLayer = this.tileMap.getObjectLayer('objects');125      this.platform.setCollisionByExclusion([-1]);126      //this.deadly.setCollisionByProperty({ collides: true });127      this.deadly.setCollisionByExclusion([-1]);128      // this.platform.setCollisionByProperty({ collides: true });129      this.matter.world.convertTilemapLayer(this.platform);130      this.matter.world.convertTilemapLayer(this.deadly);131      132      this.matter.world.setBounds(0, 0, this.tileMap.widthInPixels, this.tileMap.heightInPixels);133      this.cameras.main.setBounds(0, 0, this.tileMap.widthInPixels, this.tileMap.heightInPixels);134  135      136      this.exitGroup = this.add.group();137      this.killingBlock = this.add.group();138      this.objectsLayer.objects.forEach( object => {139        if (object.name === "steam") {140          this.dangerousLayer.add(new SteamTube(this, object.x, object.y, object.type));141        }142        if (object.name === "exit") {143          new Turn(this, object.x, object.y, object.width, object.height, object.type)144        }145      });146    }147    hitDeadlyLayer(tile) {148      if (!this.player.dead) {149        this.player.sprite.anims.play("moriarty", true);150        this.cameras.main.shake(100);151        this.lightning.lightning();152        this.player.death();153      }154    }155      loadAudios () {156        this.audios = {157          "stage": this.sound.add("stage"),158        };159      }160      playAudio(key) {161        this.audios[key].play();162      }163      playRandom(key) {164        this.audios[key].play({165          rate: Phaser.Math.Between(1, 1.5),166          detune: Phaser.Math.Between(-1000, 1000),167          delay: 0168        });169      }170      playMusic (theme="music") {171        this.theme = this.sound.add(theme);172        this.theme.stop();173        this.theme.play({174          mute: false,175          volume: 0.4,176          rate: 1,177          detune: 0,178          seek: 0,179          loop: true,180          delay: 0181      })182      }183    update() {184    }185    finishScene () {186      this.theme.stop();187      this.time.delayedCall(500, () => {188        this.scene.start("outro");189      }, null, this)190    }191    updateScore (points = 0) {192        const score = +this.registry.get("score") + points;193        this.registry.set("score", score);194        this.scoreText.setText(Number(score).toLocaleString());195    }196    get midPoint () {197      return{ x: this.cameras.main.worldView.x + this.cameras.main.width / 2,198              y: this.cameras.main.worldView.y + this.cameras.main.height / 2199      };200  }...BlueBrain.js
Source:BlueBrain.js  
1module.exports = function(RED) {2 3    var events = require('events');4    var BlueBrainDevice = require('./BlueBrainDevice');5    var beanScanner = require('./BlueBrainScanner.js');6    7    function BlueBrain(n) {  8        var verboseLog = function (msg){9            if (RED.settings.verbose) {10                this.log(msg);11            }12        }.bind(this)13        14        15        var node= this;          16        RED.nodes.createNode(node,n);  17        events.EventEmitter.call(this);18        verboseLog("A Cannybots config node is being instantiated");19               20        // Unlimited listeners21        this.setMaxListeners(0);22  23        node.log("uuid = " +JSON.stringify(n.uuid));24        node.log("name = " +JSON.stringify(n.name));25        node.botName="no-name";26        node.name = n.name;27        node.uuid = n.uuid;28        node.device;29        30        node.connectiontype = "constant";//n.connectiontype;31        node._isAttemptingConnection = false;32        node._isConnectedAndSetUp = false;33       34        // BlueBrain Device discovery and events35       36        // Called after a Bean has been disconnected37        var _hasDisconnected = function (){38            node._isConnectedAndSetUp = false;39            node._isAttemptingConnection = false;40            node.status({fill:"red",shape:"ring",text:"disconnected"});   41            verboseLog("We disconnected from the Cannybot node with name \"" + node.name + "\" and uuid " + node.uuid);42            43            node.emit("disconnected");44            //beanScanner.startScanning();45            46            if(node.connectiontype == 'constant' &&47                node.isBeingDestroyed !== true){48                _attemptConnection();49            }50        }.bind(node);51       52        // Called after a Bean has successfully connected53        var _hasConnected = function (){54            node._isConnectedAndSetUp = true;55            node.status({fill:"green",shape:"dot",text:"connected to '"+ node.device._peripheral.advertisement.localName+"'"});56            verboseLog("We connected to the Cannybot with node name \"" + node.name + "\" and device uuid " + node.device.uuid);57            node.emit("connected");58        }.bind(node);59       60       // This function will attempt to connect to a Bean. 61        var _attemptConnection = function(){62            if (node._isConnectedAndSetUp === true) {63                return false;64            }65            if(node._isAttemptingConnection === true ||66                node.isBeingDestroyed === true){ 67                verboseLog("Already in a connection attempt to the Cannybot with name \"" + node.name + "\"");68                return false; 69            }70            verboseLog("Scanning for the Cannybot with addr \"" + node.name + "\"");71            node._isAttemptingConnection = true;72            node.emit("searching");73            var onDiscovery = function(device) {74                node.device = device;75                verboseLog("We found a desired Cannybot Cannybot with name \"" + node.name + "\" and uuid " + node.device.uuid);76                node.emit("connecting");77                node.device.connectAndSetUp(function(){78                    node._isAttemptingConnection = false;79                    node.device.once('disconnect', _hasDisconnected);80                    _hasConnected();81                }.bind(node))82            }.bind(node)83            BlueBrainDevice.discoverWithFilter(function(device) {84                verboseLog("looking for node.uuid = " + node.uuid + ", got device.uuid = " + device.uuid);85                if ( (node.uuid !== undefined) && (device.uuid !== node.uuid)) 86                    return false;87                return (device.uuid === node.uuid) || (device._peripheral.advertisement.localName === node.name);88            }.bind(node), onDiscovery);89            return true;90        }.bind(node)91       92       93        // Used to check if this node is currently conencted to a Cannybot94        var _isConnected = function (){95            if(node.device96                && node._isConnectedAndSetUp === true97                && node.device._peripheral.state == 'connected'98                && ((node.device.connectAndSetUp) ? node.device.connectAndSetUp === true : true)){99                return true;100            }else{101                return false;102            }103        }.bind(node)104        105        var _performFunctionWhenConnected = function(aFunction){106            if(_isConnected() === true){107                aFunction.call(node);108            }else{109                _attemptConnection(node.connectiontimeout);110            }111        }.bind(node)112        113        114        115        var write = function(data, done){116            _performFunctionWhenConnected(function(){117                node.device.write(data, done);118            })119        }.bind(node)120        121        // This is a second precaution in case the "disconnect" event isn't reached 122        if(node.connectiontype === 'constant'){123            // Queue up a call to attempt initial connection. 124            // This lets the Bean nodes that depend on this configuration get setup before connction is attempted125            setImmediate(function(){126                _attemptConnection();127            })128            // Check connection status periodically and attempt to reconnect if disconnceted129            node.reconnectInterval = setInterval(function(){130                if(_isConnected() === false){131                    _attemptConnection();132                }else{133                    verboseLog("We are currently connected to the Cannybot with uuid \"" + node.uuid + "\"");134                }135            }.bind(node), 10*1000)136        }137        // This event handle this Bean config node being destroyed138        node.on("close", function(done) {139            verboseLog("A Cannybot config node is being destroyed");140            node.isBeingDestroyed = true;141            clearInterval(node.reconnectInterval);142            //beanScanner.stopScanning();143            // This is a hack. It clears all scan requests for noble-device. 144            // If every other bean config node isn't also being reset now, then we have issues145            BlueBrainDevice.emitter.removeAllListeners('discover');  146            if (node._isConnected()) {147                node.device.disconnect(function(){148                    verboseLog("A Cannybot config node is finished being destroyed");149                    done();150                }.bind(node));151            }else{152                verboseLog("A Cannybot config node is finished being destroyed");153                done();154            }155        });156    157    158 159    }160    RED.nodes.registerType("BlueBrain",BlueBrain);  161    162    RED.httpAdmin.get("/discoveredbluebrains",function(req,res) {163        res.writeHead(200, {'Content-Type': 'text/plain'});164        var beans = beanScanner.getDiscoveredBeans();165        var beanReport =[];166        for (i = 0; i < beans.length; i++) {167            beanReport.push({168                "name":beans[i]._peripheral.advertisement.localName,169                "uuid":beans[i].uuid,170                "rssi":beans[i]._peripheral.rssi171            });172        }173        res.write(JSON.stringify(beanReport));174        res.end();175    });...BlueBrainBLE.js
Source:BlueBrainBLE.js  
1module.exports = function(RED) {2 3    var events = require('events');4    var BlueBrainDevice = require('./BlueBrainDevice');5    var beanScanner = require('./BlueBrainScanner.js');6    7    function BlueBrain(n) {  8        var verboseLog = function (msg){9            if (RED.settings.verbose) {10                this.log(msg);11            }12        }.bind(this)13        14        15        var node= this;          16        RED.nodes.createNode(node,n);  17        events.EventEmitter.call(this);18        verboseLog("A Cannybots config node is being instantiated");19               20        // Unlimited listeners21        this.setMaxListeners(0);22  23        node.log("uuid = " +JSON.stringify(n.uuid));24        node.log("name = " +JSON.stringify(n.name));25        node.botName="no-name";26        node.name = n.name;27        node.uuid = n.uuid;28        node.device;29        30        node.connectiontype = "constant";//n.connectiontype;31        node._isAttemptingConnection = false;32        node._isConnectedAndSetUp = false;33       34        // BlueBrain Device discovery and events35       36        // Called after a Bean has been disconnected37        var _hasDisconnected = function (){38            node._isConnectedAndSetUp = false;39            node._isAttemptingConnection = false;40            node.status({fill:"red",shape:"ring",text:"disconnected"});   41            verboseLog("We disconnected from the Cannybot with name \"" + node.name + "\" and uuid " + node.device.uuid);42            node.emit("disconnected");43            44            if(node.connectiontype == 'constant' &&45                node.isBeingDestroyed !== true){46                _attemptConnection();47            }48        }.bind(node);49       50        // Called after a Bean has successfully connected51        var _hasConnected = function (){52            node._isConnectedAndSetUp = true;53            node.status({fill:"green",shape:"dot",text:"connected to '"+ node.device._peripheral.advertisement.localName+"'"});54            verboseLog("We connected to the Cannybot with name \"" + node.name + "\" and uuid " + node.device.uuid);55            node.emit("connected");56        }.bind(node);57       58       // This function will attempt to connect to a Bean. 59        var _attemptConnection = function(){60            if(node._isAttemptingConnection === true ||61                node.isBeingDestroyed === true){ 62                verboseLog("Already in a connection attempt to the Bean with name \"" + node.name + "\"");63                return false; 64            }65            verboseLog("Scanning for the Cannybot with addr \"" + node.name + "\"");66            node._isAttemptingConnection = true;67            node.emit("searching");68            var onDiscovery = function(device) {69                node.device = device;70                verboseLog("We found a desired Cannybot Cannybot with name \"" + node.name + "\" and uuid " + node.device.uuid);71                node.emit("connecting");72                node.device.connectAndSetUp(function(){73                    node._isAttemptingConnection = false;74                    node.device.once('disconnect', _hasDisconnected);75                    _hasConnected();76                }.bind(node))77            }.bind(node)78            BlueBrainDevice.discoverWithFilter(function(device) {79                verboseLog("looking for node.uuid = " + node.uuid + ", got device.uuid = " + device.uuid);80                if ( (node.uuid !== undefined) && (device.uuid !== node.uuid)) 81                    return false;82                return (device.uuid === node.uuid) || (device._peripheral.advertisement.localName === node.name);83            }.bind(node), onDiscovery);84            return true;85        }.bind(node)86       87       88        // Used to check if this node is currently conencted to a Cannybot89        var _isConnected = function (){90            if(node.device91                && node._isConnectedAndSetUp === true92                && node.device._peripheral.state == 'connected'93                && ((node.device.connectAndSetUp) ? node.device.connectAndSetUp === true : true)){94                return true;95            }else{96                return false;97            }98        }.bind(node)99        100        var _performFunctionWhenConnected = function(aFunction){101            if(_isConnected() === true){102                aFunction.call(node);103            }else{104                _attemptConnection(node.connectiontimeout);105            }106        }.bind(node)107        108        109        110        var write = function(data, done){111            _performFunctionWhenConnected(function(){112                node.device.write(data, done);113            })114        }.bind(node)115        116        // This is a second precaution in case the "disconnect" event isn't reached 117        if(node.connectiontype === 'constant'){118            // Queue up a call to attempt initial connection. 119            // This lets the Bean nodes that depend on this configuration get setup before connction is attempted120            setImmediate(function(){121                _attemptConnection();122            })123            // Check connection status periodically and attempt to reconnect if disconnceted124            node.reconnectInterval = setInterval(function(){125                if(_isConnected() === false){126                    _attemptConnection();127                }else{128                    verboseLog("We are currently connected to the Cannybot with uuid \"" + node.uuid + "\"");129                }130            }.bind(node), 10*1000)131        }132        // This event handle this Bean config node being destroyed133        node.on("close", function(done) {134            verboseLog("A Cannybot config node is being destroyed");135            node.isBeingDestroyed = true;136            clearInterval(node.reconnectInterval);137            //beanScanner.stopScanning();138            // This is a hack. It clears all scan requests for noble-device. 139            // If every other bean config node isn't also being reset now, then we have issues140            BlueBrainDevice.emitter.removeAllListeners('discover');  141            if (node._isConnected()) {142                node.device.disconnect(function(){143                    verboseLog("A Cannybot config node is finished being destroyed");144                    done();145                }.bind(node));146            }else{147                verboseLog("A Cannybot config node is finished being destroyed");148                done();149            }150        });151    152    153 154    }155    RED.nodes.registerType("BlueBrain",BlueBrain);  156    157    RED.httpAdmin.get("/discoveredbluebrains",function(req,res) {158        res.writeHead(200, {'Content-Type': 'text/plain'});159        var beans = beanScanner.getDiscoveredBeans();160        var beanReport =[];161        for (i = 0; i < beans.length; i++) {162            beanReport.push({163                "name":beans[i]._peripheral.advertisement.localName,164                "uuid":beans[i].uuid,165                "rssi":beans[i]._peripheral.rssi166            });167        }168        res.write(JSON.stringify(beanReport));169        res.end();170    });...gridManager.js
Source:gridManager.js  
1function drawGrid() {2    processData = (response) => {3        var hosts = response['data']['results']4        var nodes = new vis.DataSet([]);5        var edges = new vis.DataSet([]);6        var color_border = 'green'7        var hostsUp = 08        var hostsDown = 0;9        var font_size = 0;10        var hostsUnreachable = 0;11        var level = 0;12        var x_pos = 1;13        num_cols = calculateNumCols(hosts.length);14        // num_cols = 1715        // return;16        if (isInFullscreenMode()) {17            font_color = "white"18        } else {19            font_color = "black"20        }21        for (i = 0; i < hosts.length; i++) {22            if (hosts[i]['attrs'].state === 0) {23                color_border = 'green';24                color_background = 'rgba(0, 204, 3, 0.25)'25                font_size = 0;26                hostsUp++;27            } else if (hosts[i]['attrs'].state === 1 && !hosts[i]['attrs'].last_reachable) {28                font_size = 20;29                color_border = "purple";30                color_background = 'rgba(98, 0, 178, 0.25)'31                hostsUnreachable++;32            } else {33                font_size = 20;34                color_border = "red";35                color_background = 'rgba(204, 0, 0, 0.25)'36                hostsDown++;37            }38            if (i % num_cols === 0) {39                level = level + 1;40                x_pos = 041            } else {42                x_pos += 1;43            }44            nodes.update({45                id: hosts[i].name,46                level: level,47                borderWidth: 2,48                label: hosts[i].name,49                x: x_pos * 205,50                y: level * 205,51                color: {52                    border: color_border,53                    background: color_background54                },55                font: {56                    size: font_size,57                    color: font_color,58                    vadjust: -15059                },60            });61        }62        var networkData = {63            nodes: nodes,64            edges: edges65        };66        var container = document.getElementById('grid-container');67        const networkOptions = {68            nodes: {69                shape: 'square',70                fixed: true,71                size: 100,72                scaling: {73                    min: 1,74                    max: 15,75                    label: {76                        enabled: false,77                        min: 14,78                        max: 30,79                        maxVisible: 30,80                        drawThreshold: 581                    },82                },83            }84        };85        var network = new vis.Network(container, networkData, networkOptions);86        if (isInFullscreenMode()) {87            fullscreenMode(hosts, network, hostsDown, hostsUp, hostsUnreachable)88        } else {89            startListeners(network)90        }91    }92    processError = (error) => {93        // errors[error['type']] = error['data']94        throw error;95    }96    var hostPromise = getHosts().then(processData, processError)97    function startListeners(network) {98        network.on("click", function (params) { //double click on node listener99            if (params.nodes[0] != undefined) {100                let hostMonitoringAddress = '';101                if (location.href.indexOf('/icingaweb2') > 1) {102                    103                    hostMonitoringAddress = 'icingaweb2/monitoring/host/show?host='104                } else {105                    hostMonitoringAddress = 'monitoring/host/show?host=';106                }107                location.href = './statusGrid#!/' + hostMonitoringAddress + params.nodes[0]; //redirect to host info page.108            }109        });110        network.on('resize', (params) => {111            isBeingDestroyed = (params.width === 0 && params.height === 0)112            if (!isBeingDestroyed) {113                drawGrid()114                network.off();115                network.destroy();116            } else {117                network.off();118                network.destroy();119            }120        })121    }122    function calculatePercentage(num, total) {123        return " (" + Math.round((num / total) * 100) + "%) "124    }125    function updateTime() {126        setTimeout(() => {127            var date = new Date();128            $('#hud-title').html('<h1>' + date + '</h1>')129            updateTime();130        }, 1000);131    }132    function startRefreshTimeout(network) {133        setTimeout(function () {134            network.destroy();135            drawGrid();136        }, 60000);137    }138    function fullscreenMode(hosts, network, hostsDown, hostsUp, hostsUnreachable) {139        updateTime();140        var date = new Date();141        var timeUpdated = date;142        $('#hud-down').html("<h1>" + hostsDown + calculatePercentage(hostsDown, hosts.length) + ' Hosts DOWN' + "</h1>");143        $('#hud-unreachable').html('<h1>' + hostsUnreachable + calculatePercentage(hostsUnreachable, hosts.length) + ' Hosts UNREACHABLE' + '</h1>');144        $('#hud-up').html('<h1>' + hostsUp + calculatePercentage(hostsUp, hosts.length) + ' Hosts UP' + '</h1>');145        $('#hud-title').html('<h1>' + timeUpdated + '</h1>');146        $('.controls').hide();147        $('#grid-container').css("background-color", '#262626');148        $('#grid-container').css("height", '90%')149        $('#main').css("width", '100%');150        $('#main').css("height", '100%');151        $('#hud').css('display', 'block');152        startRefreshTimeout(network);153    }154    function isInFullscreenMode() {155        return (window.location.href.indexOf('Fullscreen') > -1)156    }157    function isInMonitoringMode() {158        return (window.location.href.indexOf('monitoring') > -1)159    }160    function calculateNumCols(numHosts) {161        let screenRatio = Math.round(($('#grid-container').innerWidth() / $('#grid-container').innerHeight()) * 10) / 10162        for (i = 0; i < numHosts; i++) {163            for (y = 0; y < numHosts; y++) {164                ratio = Math.round((y / i) * 10) / 10165                total = Math.round(i * y)166                if (ratio === screenRatio) {167                    if (total >= numHosts) {168                        return (y)169                    }170                }171            }172        }173    }...matter detect collision with tile.js
Source:matter detect collision with tile.js  
1var config = {2    type: Phaser.AUTO,3    width: 800,4    height: 600,5    backgroundColor: '#000000',6    parent: 'phaser-example',7    physics: {8        default: 'matter',9        matter: {10            gravity: { y: 1 },11            enableSleep: true12        }13    },14    scene: {15        preload: preload,16        create: create,17        update: update18    }19};20var game = new Phaser.Game(config);21var controls;22function preload ()23{24    this.load.spritesheet('balls', 'assets/sprites/balls.png', { frameWidth: 17, frameHeight: 17 });25    this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/tileset-collision-shapes.json');26    this.load.image('kenny_platformer_64x64', 'assets/tilemaps/tiles/kenny_platformer_64x64.png');27}28function create ()29{30    var map = this.make.tilemap({ key: 'map' });31    var tileset = map.addTilesetImage('kenny_platformer_64x64');32    var layer = map.createDynamicLayer(0, tileset, 0, 0);33    // Set colliding tiles before converting the layer to Matter bodies!34    layer.setCollisionByProperty({ collides: true });35    // Convert the layer. Any colliding tiles will be given a Matter body. If a tile has collision36    // shapes from Tiled, these will be loaded. If not, a default rectangle body will be used. The37    // body will be accessible via tile.physics.matterBody.38    this.matter.world.convertTilemapLayer(layer);39    this.matter.world.setBounds(map.widthInPixels, map.heightInPixels);40    this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);41    this.cameras.main.setScroll(95, 100);42    // Change the label of the Matter body on the tiles that should kill the bouncing balls. This43    // makes it easier to check Matter collisions.44    layer.forEachTile(function (tile) {45        // In Tiled, the platform tiles have been given a "type" property which is a string46        if (tile.properties.type === 'lava' || tile.properties.type === 'spike')47        {48            tile.physics.matterBody.body.label = 'dangerousTile';49        }50    });51    // Drop bouncy, Matter balls on pointer down. Apply a custom label to the Matter body, so that52    // it is easy to find the collision we care about.53    this.input.on('pointerdown', function () {54        var worldPoint = this.input.activePointer.positionToCamera(this.cameras.main);55        for (var i = 0; i < 5; i++)56        {57            var x = worldPoint.x + Phaser.Math.RND.integerInRange(-5, 5);58            var y = worldPoint.y + Phaser.Math.RND.integerInRange(-5, 5);59            var frame = Phaser.Math.RND.integerInRange(0, 5);60            this.matter.add.image(x, y, 'balls', frame, { restitution: 1, label: 'ball' });61        }62    }, this);63    // Loop over all the collision pairs that start colliding on each step of the Matter engine.64    this.matter.world.on('collisionstart', function (event) {65        for (var i = 0; i < event.pairs.length; i++)66        {67            // The tile bodies in this example are a mixture of compound bodies and simple rectangle68            // bodies. The "label" property was set on the parent body, so we will first make sure69            // that we have the top level body instead of a part of a larger compound body.70            var bodyA = getRootBody(event.pairs[i].bodyA);71            var bodyB = getRootBody(event.pairs[i].bodyB);72            if ((bodyA.label === 'ball' && bodyB.label === 'dangerousTile') ||73                (bodyB.label === 'ball' && bodyA.label === 'dangerousTile'))74            {75                const ballBody = bodyA.label === 'ball' ? bodyA : bodyB;76                const ball = ballBody.gameObject;77                // A body may collide with multiple other bodies in a step, so we'll use a flag to78                // only tween & destroy the ball once.79                if (ball.isBeingDestroyed)80                {81                    continue;82                }83                ball.isBeingDestroyed = true;84                this.matter.world.remove(ballBody);85                this.tweens.add({86                    targets: ball,87                    alpha: { value: 0, duration: 150, ease: 'Power1' },88                    onComplete: function (ball) { ball.destroy(); }.bind(this, ball)89                });90            }91        }92    }, this);93    var cursors = this.input.keyboard.createCursorKeys();94    var controlConfig = {95        camera: this.cameras.main,96        left: cursors.left,97        right: cursors.right,98        up: cursors.up,99        down: cursors.down,100        speed: 0.5101    };102    controls = new Phaser.Cameras.Controls.FixedKeyControl(controlConfig);103    var help = this.add.text(16, 16, 'Left-click to drop balls.\nTry dropping the balls on the spikes or lava.', {104        fontSize: '18px',105        padding: { x: 10, y: 5 },106        backgroundColor: '#ffffff',107        fill: '#000000'108    });109    help.setScrollFactor(0);110}111function update (time, delta)112{113    controls.update(delta);114}115function getRootBody (body)116{117    if (body.parent === body) { return body; }118    while (body.parent !== body)119    {120        body = body.parent;121    }122    return body;...bootstrap.js
Source:bootstrap.js  
1/**2 * @module patches/bootstrap3 * @desc Work around boostrap problems.4 * @author Louis-Dominique Dubeau5 * @license MPL 2.06 * @copyright Mangalam Research Center for Buddhist Languages7 */8define(/** @lends auto */ function f(require) {9  "use strict";10  var $ = require("jquery");11  require("bootstrap");12  var Tooltip = $.fn.tooltip.Constructor;13  var ttVersion = Tooltip.VERSION;14  function parseVersion(version) {15    version = version.split(".");16    if (version.length < 3) {17      // Normalize to length 3. The length is at least 1.18      version = version.concat([0, 0]).slice(0, 3);19    }20    return version.reduce(function step(acc, x) {21      return (acc * 1000) + parseInt(x);22    }, 0);23  }24  function override(name, builder) {25    var orig = Tooltip.prototype[name];26    Tooltip.prototype[name] = builder(orig);27  }28  //29  // Work around this bug:30  // https://github.com/twbs/bootstrap/issues/2051131  //32  if (parseVersion(ttVersion) >= parseVersion("3.3.7")) {33    override("destroy", function buildDestroy(orig) {34      return function destroy() {35        if (this.isBeingDestroyed) {36          return;37        }38        this.isBeingDestroyed = true;39        orig.apply(this, arguments);40      };41    });42    override("show", function buildShow(orig) {43      return function show() {44        if (this.isBeingDestroyed) {45          return;46        }47        orig.apply(this, arguments);48      };49    });50    // We cannot trivially override ``hide`` to check for51    // ``isBeingDestroyed`` because ``destroy`` calls ``hide``. And52    // due to the override above ``isBeingDestroyed`` would always be53    // true and ``hide`` would do nothing.54  }55});...codeview.js
Source:codeview.js  
1odoo.define('web_editor.wysiwyg.plugin.codeview', function (require) {2'use strict';3var core = require('web.core');4var Plugins = require('web_editor.wysiwyg.plugins');5var registry = require('web_editor.wysiwyg.plugin.registry');6var _t = core._t;7var CodeviewPlugin = Plugins.codeview.extend({8    /**9     * @override10     */11    activate: function () {12        this._super();13        if (this.$codable.height() === 0) {14            this.$codable.height(180);15        }16        this.context.invoke('editor.hidePopover');17        this.context.invoke('editor.clearTarget');18    },19    /**20     * @override21     */22    deactivate: function () {23        if (24            this.context.invoke('HelperPlugin.hasJinja', this.context.invoke('code')) &&25            !this.isBeingDestroyed26        ) {27            var message = _t("Your code contains JINJA conditions.\nRemove them to return to WYSIWYG HTML edition.");28            this.do_warn(_t("Cannot edit HTML"), message);29            this.$codable.focus();30            return;31        }32        this._super();33        this.$editable.css('height', '');34    },35    /**36     * @override37     */38    destroy: function () {39        this.isBeingDestroyed = true;40        this._super();41    },42    /**43     * Force activation of the code view.44     */45    forceActivate: function () {46        if (!this.isActivated()) {47            this.activate();48        }49    },50});51registry.add('codeview', CodeviewPlugin);52return CodeviewPlugin;...Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3  const browser = await chromium.launch();4  const context = await browser.newContext();5  const page = await context.newPage();6  await page.screenshot({ path: `example.png` });7  await browser.close();8})();Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3  const browser = await chromium.launch({ headless: false });4  const context = await browser.newContext();5  const page = await context.newPage();6  await page.waitForTimeout(5000);7  await page.close();8  await browser.close();9})();10const { chromium } = require('playwright');11(async () => {12  const browser = await chromium.launch({ headless: false });13  const context = await browser.newContext();14  const page = await context.newPage();15  await page.waitForTimeout(5000);16  await page.close();17  await browser.close();18})();19const { chromium } = require('playwright');20(async () => {21  const browser = await chromium.launch({ headless: false });22  const context = await browser.newContext();23  const page = await context.newPage();24  await page.waitForTimeout(5000);25  await page.close();26  await browser.close();27})();28const { chromium } = require('playwright');29(async () => {30  const browser = await chromium.launch({ headless: false });31  const context = await browser.newContext();32  const page = await context.newPage();33  await page.waitForTimeout(5000);34  await page.close();35  await browser.close();36})();37const { chromium } = require('playwright');38(async () => {39  const browser = await chromium.launch({ headless: false });40  const context = await browser.newContext();41  const page = await context.newPage();42  await page.waitForTimeout(5000);43  await page.close();44  await browser.close();45})();46const { chromium } = require('playwright');47(async () => {48  const browser = await chromium.launch({ headless: false });49  const context = await browser.newContext();50  const page = await context.newPage();51  await page.goto('httpsUsing AI Code Generation
1const { chromium } = require('playwright');2(async () => {3    const browser = await chromium.launch();4    const page = await browser.newPage();5    await page.waitForTimeout(10000);6    await browser.close();7})();8test('new page is created and closed', async () => {9    const browser = await chromium.launch();10    const page = await browser.newPage();11    await page.waitForTimeout(10000);12    await browser.close();13    expect(page._page.isBeingDestroyed()).toBe(true);14});15test('new page is created and closed', async () => {16    const browser = await chromium.launch();17    const page = await browser.newPage();18    await page.waitForTimeout(10000);19    await browser.close();20    expect(page._page.isBeingDestroyed()).toBe(true);21    expect(page._page.isCreated()).toBe(true);22});23test('user is logged in and logged out', async () => {24    const browser = await chromium.launch();Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3  const browser = await chromium.launch();4  const page = await browser.newPage();5  await page.screenshot({ path: 'example.png' });6  await browser.close();7})();Using AI Code Generation
1const { PlaywrightInternals } = require('playwright');2const { chromium } = require('playwright-chromium');3(async () => {4    const browser = await chromium.launch();5    const page = await browser.newPage();6    await page.screenshot({path: 'google.png'});7    await browser.close();8    console.log(PlaywrightInternals.isBeingDestroyed(browser));9})();10const { PlaywrightInternals } = require('playwright');11const { chromium } = require('playwright-chromium');12(async () => {13    const browser = await chromium.launch();14    const page = await browser.newPage();15    await page.screenshot({path: 'google.png'});16    console.log(PlaywrightInternals.isBeingDestroyed(browser));17    await browser.close();18})();Using AI Code Generation
1import { Playwright } from 'playwright';2const browser = await Playwright.chromium.launch()3const page = await browser.newPage()4await browser.close()5import { chromium } from 'playwright';6const browser = await chromium.launch()7const page = await browser.newPage()8await browser.close()Using AI Code Generation
1const { chromium } = require('playwright');2const { Page } = require('playwright/lib/server/page');3const browser = await chromium.launch();4(async () => {5  const page = await browser.newPage();6  const internalPage = new Page(page);7  await page.close();8})();9const { chromium } = require('playwright');10const { Page } = require('playwright/lib/server/page');11const browser = await chromium.launch();12(async () => {13  const page = await browser.newPage();14  const internalPage = new Page(page);15  await page.close();16})();17const { chromium } = require('playwright');18const { Page } = require('playwright/lib/server/page');19const browser = await chromium.launch();20(async () => {21  const page = await browser.newPage();22  const internalPage = new Page(page);23  await page.close();24})();25const { chromium } = require('playwright');26const { Page } = require('playwright/lib/server/page');27const browser = await chromium.launch();28(async () => {29  const page = await browser.newPage();30  const internalPage = new Page(page);31  await page.close();32})();33const { chromium } = require('playwright');34const { Page } = require('playwright/lib/server/page');35const browser = await chromium.launch();36(async () => {37  const page = await browser.newPage();38  const internalPage = new Page(page);39  await page.close();Using AI Code Generation
1import { chromium } from 'playwright';2(async () => {3  const browser = await chromium.launch();4  await browser.close();5})();6import { chromium } from 'playwright';7describe('Playwright Internal', () => {8  it('isBeingDestroyed', async () => {9    const browser = await chromium.launch();10    await browser.close();11  });12});Using AI Code Generation
1const { Playwright } = require("playwright");2const { Browser } = Playwright;3const { chromium } = require("playwright");4const browser = await chromium.launch({ headless: false });5const context = await browser.newContext();6const page = await context.newPage();7await page.pause();8await browser.close();9Browser.prototype.isBeingDestroyed = function () {10  return this._isBeingDestroyed;11};12Context.prototype.isBeingDestroyed = function () {13  return this._isBeingDestroyed;14};15Page.prototype.isBeingDestroyed = function () {16  return this._isBeingDestroyed;17};18const { Playwright } = require("playwright");19const { Browser } = Playwright;20const { chromium } = require("playwright");21const browser = await chromium.launch({ headless: false });22const context = await browser.newContext();23const page = await context.newPage();24await page.pause();25await browser.close();26Browser.prototype.isBeingDestroyed = function () {27  return this._isBeingDestroyed;28};29Context.prototype.isBeingDestroyed = function () {30  return this._isBeingDestroyed;31};32Page.prototype.isBeingDestroyed = function () {33  return this._isBeingDestroyed;34};35const { Playwright } = require("playwright");36const { Browser } = Playwright;37const { chromium } = require("playwright");38const browser = await chromium.launch({ headless: false });39const context = await browser.newContext();40const page = await context.newPage();41await page.pause();42await browser.close();43Browser.prototype.isBeingDestroyed = function () {44  return this._isBeingDestroyed;45};LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!
