synthetixio / synpress Goto Github PK
View Code? Open in Web Editor NEWSynpress is e2e testing framework based on Cypress.io and playwright with support for metamask.
Home Page: https://synpress.io
License: MIT License
Synpress is e2e testing framework based on Cypress.io and playwright with support for metamask.
Home Page: https://synpress.io
License: MIT License
Is it possible to use Cypress plugins?
I defined these in cypress.json
:
{
"supportFile": "cypress/support/index.js",
"pluginsFile": "cypress/plugins/index.js",
}
But the plugins only seem to be loaded when using synpress open
not with synpress run
.
I would like to use cypress-file-upload
and custom commands.
I also can't see any plugin-related folders is the example project structure in the README.
Line 110 in f85eb61
I think the secretWords variable should be rename to secretWordsOrPrivateKey
SKIP_RESOURCES_WAIT
is always null
. This is because process.env.
is used to retrieve environment variable.
Cypress.env()
can be used insted for this work. But due to the fact that Cypress ignores all environment variables that do not start with CYPRESS_
need to set CYPRESS_SKIP_RESOURCES_WAIT
insted
Originally posted by saur-bh February 7, 2022
After investigation found that selector needs to be corrected in
@synthetixio/synpress/pages/metamask/notification-page.js as
{code}
const confirmSignatureRequestButton = ${notificationPage} .signature-request-footer :last-child
;
const rejectSignatureRequestButton = ${notificationPage} .signature-request-footer :first-child
;
{code}
which is
{code}
const confirmSignatureRequestButton = ${notificationPage} .request-signature__footer__sign-button
;
const rejectSignatureRequestButton = ${notificationPage} .request-signature__footer__cancel-button
;
{code}
Hey, I keep getting the following error even after doing the whole setup as described in synpress readme:
1) Connect metamask wallet
"before all" hook for "visits page":
CypressError: `cy.task('setupMetamask')` failed with the following error:
> Cannot read properties of undefined (reading 'waitForTimeout')
https://on.cypress.io/api/task
Because this error occurred during a `before all` hook we are skipping all of the remaining tests.
at http://localhost:3000/__cypress/runner/cypress_runner.js:161147:78
at tryCatcher (http://localhost:3000/__cypress/runner/cypress_runner.js:13196:23)
at Promise._settlePromiseFromHandler (http://localhost:3000/__cypress/runner/cypress_runner.js:11131:31)
at Promise._settlePromise (http://localhost:3000/__cypress/runner/cypress_runner.js:11188:18)
at Promise._settlePromise0 (http://localhost:3000/__cypress/runner/cypress_runner.js:11233:10)
at Promise._settlePromises (http://localhost:3000/__cypress/runner/cypress_runner.js:11309:18)
at _drainQueueStep (http://localhost:3000/__cypress/runner/cypress_runner.js:7903:12)
at _drainQueue (http://localhost:3000/__cypress/runner/cypress_runner.js:7896:9)
at Async.../../node_modules/bluebird/js/release/async.js.Async._drainQueues (http://localhost:3000/__cypress/runner/cypress_runner.js:7912:5)
at Async.drainQueues (http://localhost:3000/__cypress/runner/cypress_runner.js:7782:14)
From Your Spec Code:
at Context.eval (http://localhost:3000/__cypress/tests?p=node_modules\@synthetixio\synpress\support\index.js:1036:15)
From Node.js Internals:
TypeError: Cannot read properties of undefined (reading 'waitForTimeout')
at Object.initialSetup (C:\..\..\node_modules\@synthetixio\synpress\commands\metamask.js:558:37)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at setupMetamask (C:\..\..\node_modules\@synthetixio\synpress\plugins\index.js:211:7)
I run this code on package.json: "test:e2e": "start-server-and-test 'npm start' http-get://localhost:3000 'env-cmd -f .env synpress run'"
Here is my spec file:
describe("Connect metamask wallet", () => {
it('visits page', () => {
cy.visit('/')
})
})
I don't know if this is the issue but I am using react functional components instead of nextjs and no typescript.
Please help.
Line 447 in 90cafd6
Why is this default to 1
when we provide a gasConfig
?
I cannot run my tests cuz cypress thinks that cy.task('setupMetamask')
is not finished
Metamask setup goes smooth, then first test cannot start because cypress hangs on before all hook. Extending defaultCommandTimeout
does not help
On the first run (just after install synpress) i got Cannot read property 'waitForTimeout' of undefined
then error disappeared but above problem happen
1) Connect-view
Connecting
"before all" hook for "should login to app":
CypressError: `cy.task('setupMetamask')` failed with the following error:
> waiting for function failed: timeout 30000ms exceeded
tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"baseUrl": "../../node_modules",
"types": [
"cypress",
"@types/puppeteer-core",
"@synthetixio/synpress/support",
"cypress-wait-until",
"@testing-library/cypress"
],
"outDir": "./output",
"lib": ["ESNext", "dom"]
},
"include": ["**/*.*"]
}
.env
PRIVATE_KEY=...
NETWORK_NAME=BSC-Testnet
RPC_URL=https://data-seed-prebsc-1-s1.binance.org:8545/
CHAIN_ID=97
SYMBOL=BNB
BLOCK_EXPLORER=https://testnet.bscscan.com/
IS_TESTNET=true
spec
import * as connectViewAction from '../../actions/connect-view-actions';
describe('Connect-view', () => {
context('Connecting', () => {
it('should login to app', () => {
connectViewAction.connectViaMetamask();
});
});
});
...
export const connectViaMetamask = () => {
navigationActions.goToConnectView();
connectViewPage.getConnectViaMetamaskButton().click();
cy.acceptMetamaskAccess().then(connected => {
expect(connected).to.be.true;
});
};
npm ERR! code ETARGET
npm ERR! notarget No matching version found for [email protected].
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn't exist.
npm ERR! notarget
npm ERR! notarget It was specified as a dependency of 'synthetix'
npm ERR! notarget
npm ERR! A complete log of this run can be found in:
Hi thanks for this really cool tool. I have a couple of issues here. Main issue is that when I enter a custom network, the screen stays stuck on metamask screen and times out. It works fine when I use one of the pre installed networks.
I also wanted to ask if there was an easy way to add more configuration without changing it in the node modules. For example, more custom commands or events (ex. on, uncaught:error)
importPk button is now primary so selector should be importButton: `${importAccountSelector} .btn-primary`
Hi, I want to confirm the request to provide a encryption public key with synpress, but I could not find it as a custom command. Is there a way to confirm arbitrary requests to metamask independent of the type via puppeteer?
It seems that metamask doesn't work well with Synpress if it's run with "chromeWebSecurity": false
flag.
There seems to be some issues with connection between metamask and browser in this case.
In case of 1inch, I wasn't able to connect my wallet:
In case of kwenta, I was able to connect my wallet, but dapp couldn't read any balances from it.
Everything works fine with "chromeWebSecurity": true
.
https://docs.cypress.io/guides/guides/web-security.html
Couldn't find anything helpful in this topic, only issues without answers, like this one:
MetaMask/metamask-extension#6817
After running export SECRET_WORDS=some-secret-words; export RPC_URL=https:\/\/kovan.infura.io\/v3\/9aa3d95b3bc440fa88ea12eaa4456161; export CHAIN_ID=42; npx synpress run -b firefox
The resulting cypress instance not have MetaMask setup open in a separate tab, I am not sure what caused this to happen as it was setting up properly previously.
Hi, is there a function that I can use to add/import a token?
Would be nice to have typescript support
Hi again,
The changeMetamaskNetwork
is not working currently I tried to call it with and without await
but it doesn't fix the issue.
My output
CypressError: Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise.
The command that returned the promise was:
> `cy.task()`
The cy command you invoked inside the promise was:
> `cy.changeMetamaskNetwork()`
Because Cypress commands are already promise-like, you don't need to wrap them or return your own promise.
Cypress will resolve your command with whatever the final Cypress command yields.
The reason this is an error instead of a warning is because Cypress internally queues commands serially whereas Promises execute as soon as they are invoked. Attempting to reconcile this would prevent Cypress from ever resolving.
at $Cy.cy.<computed> [as changeMetamaskNetwork] (http://localhost:3000/__cypress/runner/cypress_runner.js:157795:23)
Hi - I'm working on getting synpress setup within an Angular app and getting this error:
export const welcomePageElements = {
^^^^^^
SyntaxError: Unexpected token 'export'
at wrapSafe (internal/modules/cjs/loader.js:1060:16)
at Module._compile (internal/modules/cjs/loader.js:1108:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1173:10)
at Module.load (internal/modules/cjs/loader.js:992:32)
at Module._load (internal/modules/cjs/loader.js:885:14)
at Function.f._load (electron/js2c/asar_bundle.js:5:12694)
at Module.require (internal/modules/cjs/loader.js:1032:19)
at require (internal/modules/cjs/helpers.js:72:18)
at Object.<anonymous> (/Users/Will/Desktop/Programming/aws-definer-app-v2/node_modules/@synthetixio/synpress/commands/metamask.js:10:5)
at Module._compile (internal/modules/cjs/loader.js:1152:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1173:10)
at Module.load (internal/modules/cjs/loader.js:992:32)
at Module._load (internal/modules/cjs/loader.js:885:14)
at Function.f._load (electron/js2c/asar_bundle.js:5:12694)
at Module.require (internal/modules/cjs/loader.js:1032:19)
at require (internal/modules/cjs/helpers.js:72:18)
at Object.<anonymous> (/Users/Will/Desktop/Programming/aws-definer-app-v2/node_modules/@synthetixio/synpress/plugins/index.js:3:18)
at Module._compile (internal/modules/cjs/loader.js:1152:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1173:10)
at Module.load (internal/modules/cjs/loader.js:992:32)
at Module._load (internal/modules/cjs/loader.js:885:14)
at Function.f._load (electron/js2c/asar_bundle.js:5:12694)
If I edit the file to use module.exports
instead of export const
then I can get things working. Any tips on how I can setup my environment to work without going into synpress and editing the files? Thanks!
Thanks for the great work on Synpress, this library looks awesome. Anyway I am struggling with something when I try to confirm transactions.
Steps to reproduce:
Leave env variable for metamask version blank (use the hardcoded version 9.7.1)
Execute: synpress run
Metamask is being initialized
The chosen address is visited
The user wallet is connected to the dApp
Button leading to transaction which needs confirmation from metamask is pressed.
Once needed to confirm metamask transaction, it is failed(screenshot attached)
Note:
Debugged the library and found where the confirmation is failing
cy.confirmMetamaskTransaction is calling -> confirmTransaction in ./commands/metamask.js
which is calling:
await puppeteer.waitClearAndType( newGasFee, confirmPageElements.gasFeeInput, notificationPage, );
- all the params passed to waitClearAndType defined.
The function waitClearAndType is failing on the step:
await input.click({ clickCount: 3 });
Where 'input' is defined.
I tried to replace waitClearAndType
with waitAndType
when called from confirmTransaction
and the transaction is passed successfully ( but the gas fee paid for the transaction is not right of course)
Other workaround I tried is to skip the calling of waitClearAndType
it is working as well, but there is possibility for the transaction not to be mined if the gas fee increased from the moment we triggered the transaction.
Also if some of the latest versions of Metamask is used(tried with 10.2.2), confirmMetamaskTransaction
is failing as well as in the last versions of Metamask, the confirmation page has no input field for the gas fee at all and it seems that the gas fee is recalculated by Metamask automatically. For these versions of metamask we could skip the steps for manually getting and setting the gas fee.
task.(confirmMetamaskPermissionToSpend)
CypressError
cy.task('confirmMetamaskPermissionToSpend') failed with the following error:
Cannot read property 'waitForTimeout' of undefined
The call to approve permission for spend of coins works - invokes the metamask popup
Fails on: cy.confirmMetamaskPermissionToSpend();
Hi guys,
Have somebody ever make synpress work with some CI? I'm trying to make it work with Gitlab CI, but it doesn't work.
Thanks a lot!
Best regards,
After running export NETWORK_NAME=rinkeby; export SECRET_WORDS=shuffle\ stay\ hair\ student\ wagon\ senior\ problem\ drama\ parrot\ creek\ enact\ pluck; npx synpress open
A command is executed in a loop and causes the cypress window to not open: npm exec synpress run -b firefox
Could possibly be coming from some cached value but not sure what would have caused this behavior in the first place.
my issue happens when i try to run a specific spec, then I got an 403 error, The issue seems coming from line 50 this file
https://github.com/Synthetixio/synpress/blob/master/helpers.js
Hi!
I created the Account2 by cy.createMetamaskAccount
And cy.switchMetamaskAccount
But I cannot let the Account2 connect to my website.
How can I resolve this?
Thank you!
Sorry, I can't find a way to re-open the issue in #215, so I create a new one.
When I try to add a network in docker container, it always gets stuck in here:
Lines 228 to 230 in b9c2f3f
Here's my docker-compose.yml
:
services:
synpress:
image: synthetixio/docker-e2e:14.17-debian
volumes:
- './synpress:/home/app'
- './synpress/node_modules:/home/node/app/node_modules'
entrypoint: ["tail", "-f", "/dev/null"]
environment:
- SECRET_WORDS="test test test test test test test test test test test junk"
- NETWORK_NAME="Smart Chain"
- RPC_URL="https://bsc-dataseed.binance.org/"
- CHAIN_ID="56"
- SYMBOL="BNB"
- BLOCK_EXPLORER="https://bscscan.com"
After starting the docker container, I run these commands:
npm i @synthetixio/synpress
npx synpress run --browser chrome --configFile 'tests/e2e/synpress.json'
My synpress.json has nothing special. I only changed the baseUrl
Then I always get
CypressError: `cy.screenshot()` timed out waiting `30000ms` to complete.
Because this error occurred during a `before all` hook we are skipping all of the remaining tests.
Although you have test retries enabled, we do not retry tests when `before all` or `after all` hooks fail
Could you check whether adding network works in docker? Thanks!
I have the following simple test. I've also set it up almost exactly as in the instructions. However, synpress is failing with the following error:
cy.task('setupMetamask') failed with the following error:
> waiting for function failed: timeout 30000ms exceeded
Because this error occurred during a before all hook we are skipping the remaining tests in the current suite:
Any idea what's going on?
describe('mint on the app.', () => {
before(() => {
cy.setupMetamask(
'test test test test test test test test test test test junk',
'localhost',
'Tester@1234',
).then(setupFinished => {
expect(setupFinished).to.be.true;
});
cy.visit('/')
})
it('visits the homepage and logs into web3sso.', () => {
cy.visit('/')
cy.wait(2000)
cy.get('#web3SSO').contains("Connect").click()
cy.wait(2000) // wait 2s.
cy.get('.web3modal-provider-name div').contains("MetaMask").click()
cy.wait(2000) // wait 2s.
cy.get('#headlessui-menu-button-3').should('have.text', '0xf39F');
})
})
I found some behaviors are weird and make this can't run in docker.
In this line:
synpress/commands/puppeteer.js
Line 38 in b9c2f3f
integration
, however, Cypress seems doesn't have __/#/tests/integration
suffix when running in docker, and this makes this detection failed.
I don't know why but I get stuck in this line when running with docker:
Lines 228 to 230 in b9c2f3f
Thanks!
I've tried using the module for testing, the processes such as set up wallet is ok. However, I've found the error on confirm a transaction, here is the prompt shown in Cypress.
at <unknown> (__puppeteer_evaluation_script__:1:64)
at <unknown> (__puppeteer_evaluation_script__:1:64)
at <unknown> (http://localhost:3000/__cypress/runner/cypress_runner.js:142397:20)
From previous event:
at Context.task (http://localhost:3000/__cypress/runner/cypress_runner.js:142379:16)
From Your Spec Code:
From Node.js Internals:
Error: Evaluation failed: ReferenceError: _this is not defined
at <unknown> (__puppeteer_evaluation_script__:1:64)
I've tried searching for workaround in Puppeteer but there is no clue in this case.
please delete
Reported by @DimitarTAtanasov
Hey,
So I was just trying to launch a simple test with synpress run
, the metamask extension opened in the test controlled browser but it just blocks on the wallet seed page. Synpress isn't typing my seed and I don't know why...
I checked my metamask version it's the latest 10.2.2 (so the latest).
Before running synpress run
I call a bash script that sets my environment variables.
The script line in my package.json
"test:cli": "./.secret.sh && synpress run",
Below is my .secret.sh file that runs before tests and exports my env variables (obviously SECRET_WORDS and PRIVATE_KEY values have been changed here)
export SECRET_WORDS="word word..."
export PRIVATE_KEY=abcde1234
export NETWORK=localhost // by the way is it a problem if my metamask network is called hardhat 8545?
export RPC_URL=http://127.0.0.1:8545/
export CHAIN_ID=31337
// Just a simple check to be sure my env variables where set
echo $SECRET_WORDS
echo $PRIVATE_KEY
echo $NETWORK
echo $RPC_URL
echo $CHAIN_ID
Here is the output
====================================================================================================
(Run Starting)
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Cypress: 8.3.0 │
│ Browser: Chrome 94 │
│ Specs: 1 found (connection-spec.js) │
└────────────────────────────────────────────────────────────────────────────────────────────────┘
────────────────────────────────────────────────────────────────────────────────────────────────────
Running: connection-spec.js (1 of 1)
1) "before all" hook for "An uncaught error was detected outside of a test"
0 passing (34s)
1 failing
1) "before all" hook for "An uncaught error was detected outside of a test":
CypressError: `cy.screenshot()` timed out waiting `30000ms` to complete.
Because this error occurred during a `before all` hook we are skipping all of the remaining tests.
at http://localhost:3000/__cypress/runner/cypress_runner.js:145415:22
at tryCatcher (http://localhost:3000/__cypress/runner/cypress_runner.js:13212:23)
at http://localhost:3000/__cypress/runner/cypress_runner.js:8334:41
at tryCatcher (http://localhost:3000/__cypress/runner/cypress_runner.js:13212:23)
at Promise._settlePromiseFromHandler (http://localhost:3000/__cypress/runner/cypress_runner.js:11147:31)
at Promise._settlePromise (http://localhost:3000/__cypress/runner/cypress_runner.js:11204:18)
at Promise._settlePromise0 (http://localhost:3000/__cypress/runner/cypress_runner.js:11249:10)
at Promise._settlePromises (http://localhost:3000/__cypress/runner/cypress_runner.js:11325:18)
at _drainQueueStep (http://localhost:3000/__cypress/runner/cypress_runner.js:7919:12)
at _drainQueue (http://localhost:3000/__cypress/runner/cypress_runner.js:7912:9)
at Async.../../node_modules/bluebird/js/release/async.js.Async._drainQueues (http://localhost:3000/__cypress/runner/cypress_runner.js:7928:5)
at Async.drainQueues (http://localhost:3000/__cypress/runner/cypress_runner.js:7798:14)
Warning: We failed processing this video.
This error will not alter the exit code.
TimeoutError: operation timed out
at afterTimeout (/Users/vitch/Library/Caches/Cypress/8.3.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/bluebird/js/release/timers.js:46:19)
at Timeout.timeoutTimeout [as _onTimeout] (/Users/vitch/Library/Caches/Cypress/8.3.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/bluebird/js/release/timers.js:76:13)
at listOnTimeout (internal/timers.js:554:17)
at processTimers (internal/timers.js:497:7)
(Results)
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Tests: 1 │
│ Passing: 0 │
│ Failing: 1 │
│ Pending: 0 │
│ Skipped: 0 │
│ Screenshots: 0 │
│ Video: false │
│ Duration: 34 seconds │
│ Spec Ran: connection-spec.js │
└────────────────────────────────────────────────────────────────────────────────────────────────┘
====================================================================================================
(Run Finished)
Spec Tests Passing Failing Pending Skipped
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ✖ connection-spec.js 00:34 1 - 1 - - │
└────────────────────────────────────────────────────────────────────────────────────────────────┘
✖ 1 of 1 failed (100%) 00:34 1 - 1 - -
Cypress run results: 1 total tests, 0 passed, 1 failed
I use command synpress open after this command i can't use function cy.confirmMetamaskWelcomePage() in '@synthetixio/support/index.js' and on cypress window show err = "Cannot read property 'waitForTimeout' of undefined"
how i should handle them all.
Thank you
Thanks for the good work with this wrapper. I was trying to use it and ran into some issues:
I see a lot of react in the dependencies, will this work with Vue.js?
Fails as dependency tree cant resolve.
It seems there is an issue with webpack.
I am trying to adequately understand the issue to try and suggest a fix, but I am struggling to learn fast enough :).
Hey,
So everything seems to work fine on my side except regarding the import by private key feature.
When I declare my env variable with SECRET_WORDS
everything works fine but when I try to use PRIVATE_KEY
instead the setup goes to seed phrase page of metamask anyway and gets stuck here since my SECRET_WORDS
env variable isn't set.
I tried running by setting both SECRET_WORDS
and PRIVATE_KEY
but it doesn't seem to import my account and sticks with the first address...
I also tried to call cy.importMetamaskAccount
but the function is not recognized and here is the output
"before all" hook for "Connects with metamask wallet":
TypeError: cy.importMetamaskAccount is not a function
EDIT: I might just be dumb, this probably shouldn't work with Electron, right?
Getting the following issue only when running Electron.
The first issue I was getting was with the remote debugger
CypressError: `cy.task('setupMetamask')` failed with the following error:
> request to http://localhost:9222/json/version failed, reason: connect ECONNREFUSED 127.0.0.1:9222
which I fixed by exporting ELECTRON_EXTRA_LAUNCH_ARGS=--remote-debugging-port=9222
. I'd suggest some way to handle this internally, or at least a line of documentation.
CypressError: `cy.task('setupMetamask')` failed with the following error:
> Cannot read property 'waitForTimeout' of undefined
It seems like await metamask.initialSetup({ secretWords, network, password });
from the plugin is being called before puppeteer has been been properly set up.
Note that I've configured metamask to use a custom network.
Recently came across this project when trying to see how best to test Dapps. I think it will be invaluable for the community, maybe to help support the development of it you might consider applying for a Gitcoin grant
When switching accounts in the MetaMask notification window, it would show a prompt to let you connect the next account to your dApp. However synpress switches accounts in a new tab of MetaMask (expanded view). In this case, the prompt won't show, so the new account won't be able to interact with the dApp...
I guess one workaround is that make synpress 'select all' accounts when it makes MetaMask connect to the dApp for the first time.
➜ synpress git:(master) ✗ synpress run setupMetamask('secret phase', 'localhost', 'password')
zsh: number expected
Add support for metamask post-EIP1559 (metamask >9).
Hi, @drptbl. I'm having a trouble with confirming this personal sign and eth_signTypedData_v4
request metamask popup.
I can't find proper command from the package.
Do you have an any idea for this?
Regards
I cant run synpress on win 10.
Apologies if this is redundant, but I haven't seen any reference to this in the issues. using @synthetixio/[email protected]
The launchOptions object returned by your plugin's before:browser:launch handler contained unexpected properties:
width
height
resizable
launchOptions may only contain the properties:
preferences
extensions
args
I'm passing in my env vars with dotenv-cli
and the test I'm attempting to run is just attempting to visit the landing page of a project:
describe('Metamask', () => {
before(() => {
cy.visit('/')
})
})
Hi, @drptbl.
Is there any method for changing accounts on metamask?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.