Webdriverio: Possibilidade de configurar a geração do processo de especificação de teste?

Criado em 14 abr. 2016  ·  41Comentários  ·  Fonte: webdriverio/webdriverio

O problema

De acordo com https://github.com/webdriverio/webdriverio/issues/1106#issuecomment -184728530 each test spec gets executed in a single child process .
Temos atualmente 101 .feature files (estamos usando pepino) e não podemos colocá-los em um arquivo grande.
Quando lançamos nosso script de teste, meu servidor Selenium está tentando gerar o processo 101, o que resulta em um grande atraso e preciso encerrar os processos.

Existe uma maneira de configurar esse comportamento? Precisamos ajustar nosso wdio.conf?

Ambiente

atualizado em 05/07/16

  • Versão WebdriverIO: 4.1.1
  • Versão Node.js: 4.4.6
  • Selenium Server 2.53.0
  • usando wdio testrunner
  • executando testes síncronos ou assíncronos: não importa
  • Pacotes wdio adicionais usados ​​(se aplicável):
    wdio-cucumber-framework: 0.2.0

Detalhes

Mesmo com as tags de opção de pepino como -cucumberOpts.tags=@foo , ele gerará 101 processos, embora apenas 1 recurso tenha sido marcado com @foo
(Observação: a configuração está funcionando bem com wdio 3.4.0)

Enhancement

Comentários muito úteis

Tentaremos encontrar uma maneira de contornar isso na v5

Todos 41 comentários

Eu tenho o mesmo problema +1 para corrigir isso.

@ timbru31 @AndrewKeig verifique a propriedade maxInstance . Você pode aplicá-los globalmente para todos os recursos ou um específico por recurso:

https://github.com/webdriverio/webdriverio/blob/master/examples/wdio.conf.js#L52 -L60
https://github.com/webdriverio/webdriverio/blob/master/examples/wdio.conf.js#L69 -L72

hi @ christian-bromann, temos isso definido como maxInstance:1 , mas independentemente das tags definidas, ele ainda irá gerar um processo e abrir uma janela do navegador em branco, para cada arquivo de recurso, execute 0 testes e feche-o. Ele executa os testes marcados assim que alcança o arquivo de recurso marcado.

Mesmo se um arquivo de feição estiver vazio, ele abre uma janela vazia do navegador e não faz nada, então a fecha, então parece que ele abre uma nova janela do navegador, independentemente dos testes habilitados em um arquivo de feição.

Espero que isso faça sentido ..

@AndrewKeig parece que podemos melhorar a integração do pepino aqui. Você pode registrar um problema no projeto wdio-cucumber com uma descrição detalhada para que eu possa reproduzi-lo e entendê-lo? Obrigado!

@AndrewKeig @ christian-bromann com o mesmo problema. Você pode me marcar se criar um problema? (ref https://github.com/webdriverio/wdio-cucumber-framework/issues/8)

@ christian-bromann acabei de testar isso com o mocha e estou recebendo o mesmo bug. Usei fgrep em mochaOpts para executar apenas testes específicos e descobri que uma nova sessão é inicializada no selênio, independentemente de haver testes para executar ou não.

Afinal, não parece um problema específico da estrutura de teste. É possível na API do adaptador de estrutura montar / compilar arquivos de teste antes de uma sessão de selênio ser iniciada, com base em critérios específicos da estrutura no adaptador, por exemplo, tags de recurso de pepino ou valores de configuração mocha grep / fgrep?

Eu acho que essa questão poderia ser reaberta aqui também para elaborar mais sobre isso.

Eu acho que essa questão poderia ser reaberta aqui também para elaborar mais sobre isso.

Concordo, acho que isso não pode ser resolvido no nível do framework porque a sessão do Selenium já começou se o adaptador do framework começar a funcionar. Todas as sugestões são bem-vindas. Eu estava pensando que seria melhor ter uma funcionalidade específica do wdio grep / fgrep e ignorar as do framework. A questão é como verificar com eficiência os arquivos de teste para eles.

Acho que valeria a pena pensar em adicionar outra etapa à API do adaptador de estrutura na qual os adaptadores devem analisar e retornar os arquivos de recursos / especificações necessários usando sua própria lógica específica de estrutura. Com base nesse (e em maxInstances , etc), o webdriverio pode determinar quantos processos ele precisa para gerar?

Quando um adaptador de estrutura não implementa esse método, ele pode retornar ao comportamento padrão (atual).

@attila boa ideia, espero que os métodos que determinam quais arquivos executar estejam de alguma forma disponíveis publicamente.

Tenho o mesmo problema e sei como resolvê-lo localmente.

Minha solução alternativa

npm test --suite="login" --grep="oauth"
  1. Analisar os argumentos da linha de comando (- valor grep)
  2. Obtenha todos os arquivos em nossa suíte
  3. Analise nossos casos de teste como new RegExp( describe \ s _ (\ s _ $ {name} \ s *) ) ;
  4. Passe todas as especificações filtradas para o Launcher
new WebDriverIO.Launcher('conf.js', {
    spec: [FILTERED_FILES] 
});

@ christian-bromann, podemos passar nossas especificações para o Launcher?

É muito doloroso para meus desenvolvedores.

@ christian-bromann encontrei o culpado.
Está no https://github.com/webdriverio/webdriverio/blob/master/lib/launcher.js#L194 loop while. Uma vez que a especificação é um grande glob, ele é executado em um loop e a cada vez (com a primeira especificação exibida) é chamado novamente para executar.

Em vez disso, ele deve ser chamado uma vez com todas as especificações, uma vez que o pepino lida com a própria execução com tags e não tags (tags ~ @foo ), não deveria?

Alguma ideia de como consertar / alterar esse código?

(3.4.0 era https://github.com/webdriverio/webdriverio/blob/1109adab9a5dbd1449fd035b20693d3c68d1d557/lib/launcher.js#L34)

Editar
As linhas 220-223 podem ter esta aparência

            this.startInstance(schedulableCaps[0].specs, schedulableCaps[0].caps, schedulableCaps[0].cid)
            schedulableCaps[0].availableInstances--
            schedulableCaps[0].runningInstances++
            schedulableCaps[0].specs = []

(passar todas as especificações para a instância e, em seguida, esvaziar todas as especificações para que o filtro com specs.length possa ser aplicado)

Editar 2
Isso me levou cerca de uma hora ou mais, mas tenha cuidado ao usar process.send com todo o objeto specs. No meu caso, o comprimento é> 100, resultando em uma mensagem maior do que o IPC pode manipular (veja, por exemplo, cat /proc/sys/kernel/msgmax (http://www.linuxinsight.com/proc_sys_kernel_msgmax.html).
(ideia possível: http://stackoverflow.com/q/24582213/1902598)
(Falando sobre esta linha https://github.com/webdriverio/webdriverio/blob/master/lib/launcher.js#L291)

Se alguém quiser saber como implementar uma opção --grep :

helpers.js

let path = require('path'),
    fs = require('fs');

let merge = require('deepmerge'),
    glob = require('glob');

module.exports = {
    /**
     * <strong i="8">@returns</strong> {string|undefined}
     */
    options () {
        for (let option of process.argv) {  
            let [key, value] = option.split('=');

            if (key === name) {
                return value;
            }
        }
    },

    /**
     * { <suite>: [ <files> ] }
     *
     * <strong i="9">@param</strong> {string} directory
     * <strong i="10">@param</strong> {string} additional
     * <strong i="11">@returns</strong> {Object}
     */
    suites (directory, additional = {}) {
        let files = fs.readdirSync(directory),
            cases = {};

        let grep = this.options('--grep');

        files.forEach(suite => {
            let files = path.join(directory, suite, '**/*.js'),
                debug = false;

            if (process.env.NODE_DEBUG) {
                debug = true;
            }

            files = glob.sync(files, {
                cache: true,
                debug
            });

            cases[suite] = files.filter(file => {
                if (grep) {
                    let match = new RegExp(grep);

                    if (grep && match.test(file)) {
                        return file;
                    }
                } else {
                    return file;
                }
            });
        });

        return this.extend(cases, additional);
    }

    /**
     * <strong i="12">@param</strong> {Object} x
     * <strong i="13">@param</strong> {Object} y
     * <strong i="14">@returns</strong> {Object}
     */
    extend (x, y) {
        return merge(...arguments);
    }
}

wdio.config.js

let helpers = require('./helpers');

exports.config = {
    suites: helpers.suites('tests')
}

testes

     foo
         test_1.js
         test_2.js

package.json

{
    "scripts": {
        "test"   : "wdio wdio.config.js",
    },

    "dependencies": {
        "deepmerge"           : "^0.2.10",
        "glob"                : "^7.0.5",
        "webdriverio"         : "^4.1.1",
        "wdio-spec-reporter"  : "^0.0.1",
        "wdio-mocha-framework": "^0.3.4",
    }
}

Concha

npm test -- --suite=foo --grep=test_1*;

Essa correção será colocada na base de código principal?

@wirsingj talvez. Eu esperava usar os internos do framework para fazer isso. Ainda não investiguei isso.

@ christian-bromann Legal, obrigado. Eu descobri que esse problema também mexe com o suporte de depuração do wdio-cucumber-framework ... ele abre uma porta de depuração para cada um dos processos filho. : \

Tenho tido o mesmo problema com a abertura de vários navegadores. Todo mundo ainda está usando o trabalho do @monolithed ?

Acabei de especificar o arquivo de recurso (usando pepino) por enquanto. Estávamos esperando para ver se essa correção seria um lançamento antes de usar a solução mais criativa :)

Obrigado @wirsingj Eu

@cheapaschips Estamos usando o executor de teste wdio-cucumber no modo assíncrono.

algum progresso nesta questão?

++ 1, algum status sobre isso?

não é uma solução alternativa, mas tenho usado

wdio wdio.conf.js --spec "features/scenarios/test.feature" 

isso só iniciará aquele arquivo, mas se você estiver usando tags, não terá sorte e obterá os navegadores de 1 a 1 de .recursos.

Em wdio.conf.js você pode definir uma função para specs :

specs: require('./specs-processor')(process.argv),

No meu caso:

const fs = require('fs');
const path = require('path');

const dir = require('node-dir'); // https://github.com/fshost/node-dir


/**
 * Based on https://github.com/webdriverio/cucumber-boilerplate/blob/master/src/tagProcessor.js
 * If specific tags are specified, and match the filename of a feature file, only load that/those feature files
 * Workaround for https://github.com/webdriverio/wdio-cucumber-framework/issues/8
 *
 * <strong i="11">@param</strong>  {Object} consoleArguments The arguments to parse from the console
 * <strong i="12">@return</strong> {Array}                   The specs to process
 */
module.exports = (consoleArguments) => {
  // This is required since this file is not parsed with Babel

  'use strict';

  let specs = [];

  let files = dir.files(path.join(__dirname, 'features'), {sync: true});

  consoleArguments.forEach((val) => {
    if (val.indexOf('--tags=') === 0) {
      const tags = val.replace('--tags=', '').split(',');

      tags.forEach((tagWithAtSymbol) => {
        const tag = tagWithAtSymbol.replace(/^@/, '');
        files.forEach((file) => {
          if (new RegExp(path.sep + tag + '\.feature$').test(file)) {
            file = file.replace(__dirname, '.');
            specs.push(file);
          }
        });
      });
    } else if (val.indexOf('--specs=') === 0) {
      specs = specs.concat(val.replace('--specs=', '').split(','));
    }
  });

  if (specs.length === 0) {
    specs.push('./features/**/*.feature');
  }

  return specs;
};

O que estou fazendo aqui, verificando se uma tag solicitada tem um arquivo .feature - então, se você quiser que @foo e foo.feature exista, defina specs como apenas foo.feature (ou vários arquivos de recursos para várias tags solicitadas). Você poderia ir mais longe e pesquisar os arquivos .feature para as tags solicitadas e apenas carregá-las; isso resolveria realmente esse bug, suponho. No meu caso, quando tenho uma tag que não corresponde ao nome do arquivo de recurso, declaro o arquivo spec explicitamente, por exemplo, wdio --spec=./features/foo.feature --tags=@wip

Algum progresso neste assunto?

Isso vai ser consertado no wdio ou wdio-cucumber-framework?

Eventualmente sim, mas isso não tem uma alta prioridade, pois wdio também oferece suporte a ferramentas para selecionar especificações individuais

@ christian-bromann Existe alguma solução para isso ?? ou vai ser consertado no wdio-cucumber-framework ??

Alguém tem alguma atualização sobre isso ou uma solução alternativa sobre os problemas iniciais ou preciso esperar que https://github.com/AlexGalichenko/webdriver-io-cucumber/issues/13 seja corrigido?

1 sobre este assunto, super irritante

Tentaremos encontrar uma maneira de contornar isso na v5

Há alguma solução alternativa disponível para esse problema?

não, você pode definir suítes e especificações com --spec ou --suite , então certifique-se de definir apenas os testes que realmente deseja executar

Espero ver alguma solução em breve para executar os arquivos usando tags. Enfrentando muitos problemas devido a esse problema.

Você pode usar outros utilitários além de tags para estruturar seus testes, eu nem vejo isso como um problema importante ou urgente.

Acabei de experimentar e pareceu funcionar pela primeira vez no wdio.conf.js ... provavelmente precisa de um pouco de trabalho, mas parece ok

const TagExpressionParser = require('cucumber-tag-expressions').TagExpressionParser
const tagParser = new TagExpressionParser()
...
const cucumberTags = process.env.TAGS != null ? process.env.TAGS : 'not <strong i="7">@x</strong>'
....
const expressionNode = tagParser.parse(cucumberTags)
const filesWithTags = glob.sync('./features/**/*.feature').map((file) => {
  const content = fs.readFileSync(file, 'utf8')
  if (content.length > 0) {
    const tagsInFile = content.match(/(@\w+)/g) || []
    if (expressionNode.evaluate(tagsInFile)) {
      return file
    }
  }
  return null
}).filter(x => x != null)

...

exports.config = {
  specs: filesWithTags,
...
}

Você pode passar as tags como uma variável de ambiente assim:
TAGS="<strong i="11">@smoke</strong> and @dev" ./node_modules/.bin/wdio

Tags são a maneira mais eficiente de filtrar nossos testes em relação a vários propósitos (por exemplo, caracterizar um teste se é fumaça ou regressão, se cobre appX ou appY, se cobre featureX ou featureY e outro featureZ. Quais são os outros não opções de tagging para alguém poder caracterizar por mais de um aspecto seus testes e ser capaz de acioná-los / filtrá-los para execução?

Eu estou enfrentando o mesmo problema.
Existe alguma atualização sobre como vamos consertar isso?

Existe alguma atualização sobre como vamos consertar isso?

@ ashishkhanna999 sinta-se à vontade para propor uma solução para ele. Não é trivial, por isso não foi tocado.

Eu consegui fazer um trabalho bem simples. É um pouco louco, mas funciona! Precisávamos disso porque a geração desnecessária de instâncias do Chrome estava adicionando muito tempo ao nosso tempo de implantação, pois queríamos executar um subconjunto de testes pós-implantação sem ter que duplicá-los em um arquivo de recurso específico pós-implantações. Tudo o que estou fazendo é percorrer todos os arquivos de recursos, extraindo marcas de cada arquivo (nem todos os nossos cenários são marcados, então precisava de algo um pouco mais abrangente, portanto, examinamos cada arquivo 'escolhendo' as marcas) e, em seguida, reconstruindo as arquivos em outro diretório com o recurso correto context e background . Eu tenho uma condição no campo "especificações" em wdio.conf.js para escolher o caminho se o site estiver sendo implantado, caso contrário, ele usa o caminho padrão.

specs: [
        helpers.cherryPickTags(featuresDir, taggedFeaturesDir, this_is_running_during_a_deployment) ? "./"+taggedFeaturesDir+"**/*.feature" : "./"+featuresDir+"**/*.feature"
    ],
var path = require("path");
var fs  = require('fs');

module.exports = {
    cherryPickTags:function(featuresDir, taggedFeaturesDir, this_is_running_during_a_deployment){  
        if(this_is_running_during_a_deployment)
        {
            if (!fs.existsSync(taggedFeaturesDir)) {
                console.log("Cherry picking tags from feature files...");
                fs.mkdirSync(taggedFeaturesDir);
                fs.readdir(featuresDir, (err, files) => {
                  files.forEach(file => {
                        fs.readFile(featuresDir+file, 'utf8', function(err, contents) {
                            if(contents != null){
                                var featureBody = contents.replace(/Scenario:.+|Scenario Outline:.+/s,"");
                                featureBody = featureBody.replace("@postDeploymentTests", "");
                                var tags = contents.replace(/\r\n/g, "\n").match(/@postDeploymentTests.+?^\n|@postDeploymentTests.+$/msg)
                                if(tags != null)
                                {
                                    featureBody = featureBody + tags.join("\n");
                                    fs.writeFile(taggedFeaturesDir+file, featureBody, (err) => {
                                      if (err) throw err;
                                      console.log('Feature file with tags created: ' + file);
                                    });
                                }

                            }
                        });
                  });
                });
             }
        } 
        return this_is_running_during_a_deployment;
    }
}

Se você for usar isso, lembre-se de alterar as entradas de regex para sua tag específica.

Esta página foi útil?
0 / 5 - 0 avaliações