npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

lc2

v1.5.11

Published

browser automation library

Downloads

75

Readme

http://lemonce.github.io/lemoncase2

#lemoncase2

It's a tiny language for writing tests.

Build Status

Install

npm install --save lc2

Grammar

All statements must end with a semicolon.
example
click 'here';

Identifier

  • Similar to JavaScript
    var a = 1;
  • You do not have to use 'var' keyword (there's no type check currently, haha)
    a = 1; a = true;

Datatype

Below is a list of data type you can use

  • number (e.g., 0.12, 1e-3)
  • string (e.g., 'you', "me")
  • Boolean (true/false)
  • RegExp

RegExp will be used as it is, to match against a string, if it is used with ~~ operator.
Otherwise it will generate a random string based on the regexp pattern (use randexp underneath).
Use it if you want to do some fuzzy testing.

Macro

Macro is the global setting for your case during runtime.

#TIMES [times:number|1]

// The case will run 10 times.
#TIMES 10

#INTERVAL [interval:number|3000]

// The case will wait 1000ms before start another one.
#INTERVAL 1000

#CLOCK [clock:number>5|10]

// The frequency of the engine, the engine will tick per 30ms.
#CLOCK 30

#SCREEN [width:number],[height:number]

// Set the screen to width 800px and height 600px.
#SCREEN 800,600

#AUTOSCROLL

// Auto scroll the window when trigger an instruction.
#AUTOSCROLL

Instruction keyword

[action] [selector:string] by/to [params|params1,params2]

Simulate an action

assert [exp][ in [overtime:number]]

Assert that the expression is true[ within overtime].

wait [time:number]

Wait a few time like a person.

log [exp]

Record the value of an expression.

jumpto [exp]

Jump to a URL.

refresh

Refresh the page.

process [identifier] { [statements] }

Define a test process.

Action keyword

You can not dispatch any event to an <iframe> element, so your instruction will not take effect on those elements.

Any error occurred during execution will be recorded in the log.
For example, if your target element does not exist, or you can't dispatch any action to target element.

input

Type a string into an element like <input type="text" /> or <textarea>.

// <input id="link" class="case" />
input 'div#link.case' by "hello world.";

click

Click a HTML element.

// <a href="...">Text</a>
click 'a';

// <a id="link" href="...">Text</a>
click 'a#link';

dblclick

Double click a HTML element.

// <div id="link" class="case">Text</div>
dblclick 'div#link.case';

rclick

Right click a HTML element.

// <div id="link" class="case">Text</div>
rclick 'div#link.case';

select [selector:string] by [value:string|index:number]

Select a <option> in <select> by value|index. (only works on <select> element)

// <select>
//   <option value="a"></option> // index:0
//   <option value="b"></option> // index:1 <-- this will be selected
//   <option value="c"></option> // index:2
// </select>

select "select" by 1;

// OR

select "select" by "b";

movein - beta

Trigger move enter events on a HTML element.

moveout - beta

Trigger move leave events on a HTML element.

scroll - beta

Scroll to a specific position or element on page.

Expression

  • Expression is what you will expect in any c-like language

Extended selector

When using a selector, you can use a string that is compatible with the following

  • Native querySelectorAll.
  • jQuery Sizzle ^2.3.0.
    • It means you can use some useful pseudo class like :contain().
  • iframe selector < that select elements inside <iframe>*
<!-- From top frame -->
<iframe id="top">
    #document
    <html>
        <body>
            <iframe id="project">
                #document
                <html>
                    <body>
                        <a href="./">link</a> <!-- select it. -->
                        <b>link</b>
                    </body>
                </html>
            </iframe>
        </body>
    </html>
</iframe>
  • iframe < iframe < a
  • * < * < a
  • #top < #project < a
  • * < #project < a:contain(link)

Selector operator

<# [selector:string] />

// Get the number of elements that matches the selector.
// <div id="link" class="case">Text</div>

log <# 'div'/>; // Output 1
log <# '#link'/>; // Output 1
log <# '#no'/>; // Output 0

<@ [selector:string] />

// Get the innerHTML of the 1st element that matches the selector.
// The result is a string or `false` if there's no match.

// <div id="link" class="case">Text</div>

log <@ 'div'/>; // Output Text
log <@ '#link'/>; // Output Text
log <@ '#no'/>; // Output false

<! [selector:string] />

// Check for element visibility.
// The result is `true` if such element exist && width > 0 && height > 0.
// otherwise it is false

// <div id="link" class="case">Text</div>
// <div id="link2" style="display:none">Text</div>

log <@ 'a'/>; // Output false
log <@ 'div'/>; // Output true
log <@ '#link2'/>; // Output false

Compare operator

[exp_A:string] ~~ [exp_B:string|RegExp]

  • exp_B is not a string or RegExp, false.
  • exp_A is not a string, false.
  • exp_A is not matched to exp_B(RegExp), false.
  • exp_A has a sub string like exp_B, true.
  • exp_A is matched to exp_B(RegExp), true.

[exp_A:string] !~ [exp_B:string|RegExp]

  • !(exp_A ~~ exp_B).

filter operator

Filter a expression, usually a string.
exp|filter(arg1, arg2, ...)[|filter(arg1, arg2, ...)...]

example:

"string" | substr(1, -1) | slice(0, 2);

Scope

  • Global scope. So there is no return keyword in LC2. A process has no parameter.
  • process main is the program's entry.

Example

Here are some examples for you to get started with the language.

Hello, world

process main {
    log 'hello world';
}

A typical test case

A test case that runs only once.

#TIMES 1

process main {
    jumpto '[URL]';
    wait 2000;
    ...
    [statement]
    ...
}

Typical examples

Test a user registration page.

#TIMES 1
#INTERVAL 3000

process main {
	jumpto '/#/register';
	wait 2000;
	// There are 5 text boxes.
	assert <#'#userInfoFrom input'/> === 5;
	// There is a captcha svg.
	assert <!"img.pull-right"/>;
	// There is a login button.
	assert <!"#userInfoFrom > button.btn"/>;
	// There is a home button.
	assert <@"#global-back-button"/> ~~ 'glyphicon-home';

	userNameRule = "#name-rule > div";

	// Input username length < 6
	input "#account-name" by '12345';
	assert <@userNameRule/> ~~ '不少于6个字符';

    // Input username length > 16
	input "#account-name" by /\w{17}/;
	assert <@userNameRule/> ~~ '不超过16个字符';

	// Username is blank
	input "#account-name" by '';
	assert <@userNameRule/> ~~ '用户名不为空';

	// Username is repeat.
	input "#account-name" by 'active';
	click "#account-email";
	assert <!"#name-repeat"/> && <@"#name-repeat"/> ~~ '用户名重复' in 2000;
	
	// Blank email.
	emailRule = "#email-rule > div";
	input "#account-email" by '';
	assert <@emailRule/> ~~ '邮箱不为空';

	// Error email
	input "#account-email" by 'fdsf';
	assert <@emailRule/> ~~ '请输入正确格式的邮箱';

	// Repeat email
	input "#account-email" by '[email protected]';
	click "#account-password";
	assert <!"#emial-repeat"/> && <@"#emial-repeat"/> ~~ '邮箱重复' in 2000;
	
	// Input password length < 8
	input "#account-password" by /\w{1,7}/;
	assert <@"#password-rule > div"/> ~~ '不少于8个字符';
	// Input password length >20
	input "#account-password" by /\w{20,}/;
	assert <@"#password-rule > div"/> ~~ '不超过20个字符';
	// Blank password
	input "#account-password" by '';
	assert <@"#password-rule > div"/> ~~ '密码不为空';
	// Error char.
	input "#account-password" by '测试测试测试测试';
	assert <@"#password-rule > div"/> ~~ '您输入了非法字符';
	
	// Password !== Confirm
	password = /\w{10}/;
	input "#account-password" by password;
	input "#account-password-confirm" by password + 'a';
	assert <@"#confirm-rule > div"/> ~~ '两次输入不一致';
	
}