├── README.md ├── .gitignore └── MakeApponitment.js /README.md: -------------------------------------------------------------------------------- 1 | ## Project description: 2 | - In this project, I have tried to write a code for people who have problems in getting an appointment at the Dutch Embassy in Iran. 3 | 4 | ## How it works: 5 | - In the code, you put your personal information instead of the information provided as an example and also you will enter your desired date. after that you should add a cronjob on your system or your server for runing this code for every 2 minutes. when you start to runing code, this code will try to find a appointment time for you and if it finds an empty time slot on the date you want, it will book it and save a screenshot of the booked appointment information for you in the system. 6 | 7 | ## setup project by this commands 8 | - npm int(run this command in your project folder) 9 | - npm install selenium-webdriver 10 | - npm install mocha 11 | - npm install chai 12 | - npm install chromedriver --chromedriver_version=LATEST 13 | 14 | 15 | ## edit package.json file 16 | - open package.json and edit this line 17 | "scripts": { 18 | "test": "echo \"Error: no test specified\" && exit 1" 19 | } 20 | 21 | to this: 22 | 23 | "scripts": { 24 | "test": "mocha MakeApponitment.js" 25 | } 26 | 27 | 28 | ## run file 29 | - for run file run this command: npm test 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /MakeApponitment.js: -------------------------------------------------------------------------------- 1 | const { By, Builder, until } = require("selenium-webdriver"); 2 | const { assert } = require('chai'); 3 | require('chai').should(); 4 | chrome = require('selenium-webdriver/chrome'); 5 | let screen = { 6 | width: 1920, 7 | height: 1080 8 | }; 9 | 10 | 11 | describe("make an appointment", function () { 12 | this.timeout(50000); 13 | 14 | after('Tear down', async function () { 15 | await driver.quit(); 16 | }); 17 | 18 | 19 | it('open website and select appointment type', async function(){ 20 | driver = await new Builder().forBrowser('chrome').setChromeOptions(new chrome.Options().windowSize(screen)).build(); 21 | await driver.get('https://www.vfsvisaonline.com/Netherlands-Global-Online-Appointment_Zone2/AppScheduling/AppWelcome.aspx?P=Y83R/PGUiM5WxqKHxt0UdPpZ6gYbP6R8WaUj23z35vc='); 22 | await driver.wait(until.elementLocated(By.xpath('//a[@id="plhMain_lnkSchApp"]')), 20000); 23 | await driver.findElement(By.xpath('//a[@id="plhMain_lnkSchApp"]')).click(); 24 | await driver.wait(until.elementLocated(By.xpath('//table[@id="plhMain_tbl"]')), 20000); 25 | // select request type (for another type of request just change "MVV – visa for long stay (>90 days)" to name of another request type) 26 | await driver.findElement(By.xpath('//select[@id="plhMain_cboVisaCategory"]/option[contains(text(), "MVV – visa for long stay (>90 days)")]')).click(); 27 | await driver.findElement(By.xpath('//input[@name="ctl00$plhMain$btnSubmit"]')).click(); // click on the continue button 28 | await driver.wait(until.elementLocated(By.xpath('//table[@id="Maintable"]')), 20000); 29 | }); 30 | 31 | it('enter Applicant Details', async function() { 32 | // select gender (if you are a girl or woman just change MR. to MS. or MRS. in the below line) 33 | await driver.findElement(By.xpath('//select[@id="plhMain_repAppVisaDetails_cboTitle_0"]/option[contains(text(), "MR.")]')).click(); 34 | await driver.findElement(By.xpath('//input[@id="plhMain_repAppVisaDetails_tbxFName_0"]')).sendKeys('ALI'); //first name 35 | await driver.findElement(By.xpath('//input[@id="plhMain_repAppVisaDetails_tbxLName_0"]')).sendKeys('ABAZARU'); //family name 36 | await driver.findElement(By.xpath('//input[@id="plhMain_repAppVisaDetails_tbxContactNumber_0"]')).sendKeys('09008782212'); //phone number 37 | await driver.findElement(By.xpath('//input[@id="plhMain_repAppVisaDetails_tbxEmailAddress_0"]')).sendKeys('test@gmail.com'); //email 38 | // confirm statement 39 | await driver.findElement(By.xpath('//select[@id="plhMain_cboConfirmation"]/option[contains(text(), "I confirm the above statement")]')).click(); 40 | // click on the continue button 41 | await driver.findElement(By.xpath('//input[@name="ctl00$plhMain$btnSubmit"]')).click(); 42 | }); 43 | 44 | it('select date from date picker', async function() { 45 | let month = await driver.wait(until.elementLocated(By.xpath('(//td[contains(text(), "2022")])[2]')), 20000).getText(); 46 | // In the line below, you can enter the desired date 47 | if(month=='June 2022' || month=='July 2022' || month=='August 2022') { 48 | const days = await driver.wait(until.elementsLocated(By.xpath('//td[@class="OpenDateAllocated"]')), 10000); 49 | if (typeof(days) != 'object') 50 | { 51 | assert.fail('there is not any day to select'); // Exists. 52 | } 53 | let num = (days.length)-1 54 | await days[num].click(); 55 | } 56 | else { 57 | assert.fail('the month is out of range'); 58 | } 59 | 60 | }); 61 | 62 | it('select time', async function() { 63 | await driver.wait(until.elementLocated(By.xpath('//span[@id="plhMain_lblSchAppDt"]'))); 64 | const times = await driver.wait(until.elementsLocated(By.xpath('//td/a')), 20000); 65 | await times[0].click(); 66 | await driver.wait(until.alertIsPresent(), 3000); // Wait for the alert to be displayed 67 | let alert = await driver.switchTo().alert(); // Store the alert in a variable 68 | await alert.accept(); //Press the OK button 69 | await driver.wait(until.elementLocated(By.xpath('//span[@id="lblAppInfo"][contains(text(), "Appointment Information")]'))); 70 | }); 71 | 72 | it('take screenshot', async function() { 73 | await driver.wait(until.elementLocated(By.xpath('//table[@id="dgApplett"]'))); 74 | 75 | await driver.takeScreenshot().then( 76 | function(image) { 77 | require('fs').writeFileSync('captured_image_3.png', image, 'base64'); 78 | } 79 | ); 80 | }); 81 | 82 | 83 | }); --------------------------------------------------------------------------------