├── .github ├── ISSUE_TEMPLATE │ ├── defect-report.md │ ├── feature_request.md │ └── website-incompatibility.md ├── stale.yml └── workflows │ ├── amd64_linux_clang.yml │ ├── amd64_linux_gcc.yml │ ├── amd64_windows_clang.yml │ ├── amd64_windows_gcc.yml │ ├── codestyle.yml │ └── i686_windows_gcc.yml ├── .gitignore ├── CMakeLists.txt ├── CONTRIBUTING.md ├── ChangeLog ├── INSTALL ├── LICENSE.BSD ├── README.md ├── configure ├── examples ├── arguments.js ├── child_process-examples.js ├── colorwheel.js ├── countdown.js ├── detectsniff.js ├── echoToFile.js ├── features.js ├── fibo.js ├── hello.js ├── injectme.js ├── loadspeed.js ├── loadurlwithoutcss.js ├── modernizr.js ├── module.js ├── netlog.js ├── netsniff.js ├── openurlwithproxy.js ├── outputEncoding.js ├── page_events.js ├── pagecallback.js ├── phantomwebintro.js ├── post.js ├── postjson.js ├── postserver.js ├── printenv.js ├── printheaderfooter.js ├── printmargins.js ├── rasterize.js ├── render_multi_url.js ├── responsive-screenshot.js ├── run-jasmine.js ├── run-jasmine2.js ├── run-qunit.js ├── scandir.js ├── server.js ├── serverkeepalive.js ├── simpleserver.js ├── sleepsort.js ├── stdin-stdout-stderr.js ├── universe.js ├── unrandomize.js ├── useragent.js ├── version.js ├── waitfor.js └── walk_through_frames.js ├── src ├── Info.plist ├── bootstrap.js ├── callback.cpp ├── callback.h ├── childprocess.cpp ├── childprocess.h ├── config.cpp ├── config.h ├── configurator.js ├── consts.h ├── cookiejar.cpp ├── cookiejar.h ├── crashdump.cpp ├── crashdump.h ├── encoding.cpp ├── encoding.h ├── env.cpp ├── env.h ├── filesystem.cpp ├── filesystem.h ├── linenoise │ ├── README.md │ └── src │ │ ├── README.markdown │ │ ├── example.c │ │ ├── linenoise.c │ │ ├── linenoise.h │ │ ├── utf8.c │ │ └── utf8.h ├── main.cpp ├── modules │ ├── child_process.js │ ├── cookiejar.js │ ├── fs.js │ ├── system.js │ ├── webpage.js │ └── webserver.js ├── mongoose │ ├── ReadMe.txt │ ├── mongoose.c │ └── mongoose.h ├── networkaccessmanager.cpp ├── networkaccessmanager.h ├── phantom.cpp ├── phantom.h ├── phantomjs-icon.png ├── phantomjs.qrc ├── phantomjs_win.ico ├── phantomjs_win.rc ├── qcommandline │ ├── qcommandline.cpp │ └── qcommandline.h ├── repl.cpp ├── repl.h ├── repl.js ├── system.cpp ├── system.h ├── terminal.cpp ├── terminal.h ├── utils.cpp ├── utils.h ├── webpage.cpp ├── webpage.h ├── webserver.cpp └── webserver.h ├── test ├── basics │ ├── exit0.js │ ├── exit23.js │ ├── module.js │ ├── phantom-object.js │ ├── require.js │ ├── require │ │ ├── a.js │ │ ├── b.js │ │ ├── dir │ │ │ ├── dummy.js │ │ │ ├── subdir │ │ │ │ ├── dummy.js │ │ │ │ └── loader.js │ │ │ └── subdir2 │ │ │ │ └── loader.js │ │ ├── dummy.js │ │ ├── empty.js │ │ ├── json_dummy.json │ │ ├── node_modules │ │ │ ├── dummy_file.js │ │ │ ├── dummy_module │ │ │ │ ├── libdir │ │ │ │ │ └── dummy_module.js │ │ │ │ └── package.json │ │ │ └── dummy_module2 │ │ │ │ └── index.js │ │ ├── not_found.js │ │ ├── require_spec.js │ │ ├── stubber.js │ │ ├── stubber_child.js │ │ └── thrower.js │ ├── stacktrace.js │ ├── test-server.js │ ├── timeout.js │ ├── url-utils.js │ └── version.js ├── lib │ ├── certs │ │ ├── https-snakeoil.crt │ │ └── https-snakeoil.key │ ├── fixtures │ │ ├── cat.py │ │ ├── dummy.js │ │ ├── echo.py │ │ ├── error-helper.js │ │ └── parse-error-helper.js │ ├── node_modules │ │ ├── dummy_exposed.js │ │ ├── dummy_file.js │ │ └── dummy_file2.js │ ├── testharness.js │ └── www │ │ ├── __init__.py │ │ ├── delay.py │ │ ├── echo.py │ │ ├── frameset │ │ ├── frame1-1.html │ │ ├── frame1-2.html │ │ ├── frame1.html │ │ ├── frame2-1.html │ │ ├── frame2-2.html │ │ ├── frame2-3.html │ │ ├── frame2.html │ │ └── index.html │ │ ├── hello.html │ │ ├── iframe.html │ │ ├── includejs.js │ │ ├── includejs1.html │ │ ├── includejs2.html │ │ ├── js-infinite-loop.html │ │ ├── load-images.html │ │ ├── logo.html │ │ ├── logo.png │ │ ├── missing-img.html │ │ ├── navigation │ │ ├── dest.html │ │ └── index.html │ │ ├── phantomjs.png │ │ ├── regression │ │ ├── pjs-10690 │ │ │ ├── Windsong.ttf │ │ │ ├── font.css │ │ │ ├── index.html │ │ │ └── jquery.js │ │ ├── pjs-13551 │ │ │ ├── child1.html │ │ │ ├── child1a.html │ │ │ ├── child2.html │ │ │ ├── closing-parent.html │ │ │ └── reloading-parent.html │ │ └── webkit-60448.html │ │ ├── render │ │ ├── image.jpg │ │ └── index.html │ │ ├── status.py │ │ ├── url-encoding.py │ │ └── user-agent.html ├── manual │ └── standards │ │ └── ecma-test262.js ├── module │ ├── child_process │ │ └── basics.js │ ├── cookiejar │ │ ├── cookiejar.js │ │ └── to-map.js │ ├── fs │ │ ├── basics.js │ │ ├── fileattrs.js │ │ └── paths.js │ ├── system │ │ ├── stdin.js │ │ ├── stdout-err.js │ │ └── system.js │ ├── webpage │ │ ├── abort-network-request.js │ │ ├── add-header.js │ │ ├── callback.js │ │ ├── capture-content.js │ │ ├── change-request-encoded-url.js │ │ ├── change-request-url.js │ │ ├── cjk-text-codecs.js │ │ ├── clip-rect.js │ │ ├── construction-with-options.js │ │ ├── contextclick-event.js │ │ ├── cookies.js │ │ ├── custom-headers.js │ │ ├── evaluate-broken-json.js │ │ ├── file-upload.js │ │ ├── frame-switching-deprecated.js │ │ ├── frame-switching.js │ │ ├── https-bad-cert.js │ │ ├── https-good-cert.js │ │ ├── includejs.js │ │ ├── keydown-event.js │ │ ├── keypress-event.js │ │ ├── keyup-event.js │ │ ├── load-images-no.js │ │ ├── load-images-yes.js │ │ ├── loading.js │ │ ├── local-urls-disabled-iframe.js │ │ ├── local-urls-disabled.js │ │ ├── local-urls-enabled-iframe.js │ │ ├── local-urls-enabled.js │ │ ├── long-running-javascript.js │ │ ├── modify-header.js │ │ ├── mouseclick-event.js │ │ ├── mousedoubleclick-event.js │ │ ├── mousedown-event.js │ │ ├── mousemove-event.js │ │ ├── mouseup-event.js │ │ ├── navigation.js │ │ ├── no-plugin.js │ │ ├── object.js │ │ ├── on-confirm.js │ │ ├── on-error.js │ │ ├── on-initialized.js │ │ ├── open.js │ │ ├── postdata.js │ │ ├── prompt.js │ │ ├── remove-header.js │ │ ├── render.js │ │ ├── renderBase64.js │ │ ├── renders │ │ │ ├── index.js │ │ │ ├── test.jpg │ │ │ ├── test.pdf │ │ │ ├── test.png │ │ │ └── test50.jpg │ │ ├── repaint-requested.js │ │ ├── resource-received-error.js │ │ ├── resource-request-error.js │ │ ├── scroll-position.js │ │ ├── set-content.js │ │ ├── set-frame-content.js │ │ ├── subwindows.js │ │ ├── url-encoding.js │ │ ├── user-agent.js │ │ ├── viewport-size.js │ │ ├── window.js │ │ └── zoom-factor.js │ └── webserver │ │ ├── basics.js │ │ └── requests.js ├── regression │ ├── README │ ├── pjs-10690.js │ ├── pjs-12482.js │ ├── pjs-13551.js │ └── webkit-60448.js ├── run-tests.py ├── standards │ ├── console │ │ └── console_log.js │ └── javascript │ │ ├── arrow.js │ │ ├── class.js │ │ ├── date.js │ │ ├── default.js │ │ ├── destructuring.js │ │ ├── function.js │ │ ├── isarray.js │ │ ├── let.js │ │ └── shorthand.js └── writing-tests.md ├── third-party.txt └── tools ├── format-code.sh └── import-linenoise.sh /.github/ISSUE_TEMPLATE/defect-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Defect report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the problem** 8 | A clear and concise description of what the problem is. 9 | 10 | **Versions** 11 | Which PhantomJS version? Tip: run `phantomjs --version` 12 | Which OS: Linux, Windows, macOS? 13 | 14 | **Steps to Reproduce** 15 | 1. 16 | 2. 17 | 3. 18 | 19 | **Actual behavior** 20 | What you observed. 21 | 22 | **Expected behavior** 23 | What you expected to happen instead. 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/website-incompatibility.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Website incompatibility 3 | about: Report a website not working properly 4 | 5 | --- 6 | 7 | **Summary** 8 | A concise description of the compatibility issue. 9 | 10 | **Test cases** 11 | Any URL or other web page that demonstrates the problem. 12 | 13 | **Initial analysis** 14 | If you did a preliminary troubleshooting, please share your finding. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the problem. 18 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 30 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 15 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - meta 9 | # Label to use when marking an issue as stale 10 | staleLabel: stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: false 13 | # Comment to post when closing a stale issue. Set to `false` to disable 14 | closeComment: > 15 | Due to our very limited maintenance capacity, we need to prioritize our development focus on other tasks. 16 | Therefore, this issue will be automatically closed (see #15395 for more details). 17 | In the future, if we see the need to attend to this issue again, then it will be reopened. 18 | Thank you for your contribution! 19 | -------------------------------------------------------------------------------- /.github/workflows/amd64_linux_clang.yml: -------------------------------------------------------------------------------- 1 | name: amd64_linux_clang 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | amd64_linux_clang: 8 | runs-on: ubuntu-18.04 9 | steps: 10 | - uses: actions/checkout@v2 11 | - run: sudo apt -y -qq update 12 | - run: sudo apt install -y clang cmake qt5-default libqt5webkit5-dev python 13 | name: Install requirements 14 | - run: clang++ --version && cmake --version && qmake --version && python --version 15 | name: Display tools version 16 | - run: CC=clang CXX=clang++ ./configure 17 | - run: make 18 | - run: file ./bin/phantomjs 19 | - run: ./bin/phantomjs --version 20 | - run: make check 21 | -------------------------------------------------------------------------------- /.github/workflows/amd64_linux_gcc.yml: -------------------------------------------------------------------------------- 1 | name: amd64_linux_gcc 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | amd64_linux_gcc: 8 | runs-on: ubuntu-18.04 9 | steps: 10 | - uses: actions/checkout@v2 11 | - run: sudo apt -y -qq update 12 | - run: sudo apt install -y g++ cmake qt5-default libqt5webkit5-dev python 13 | name: Install requirements 14 | - run: g++ --version && cmake --version && qmake --version && python --version 15 | name: Display tools version 16 | - run: ./configure 17 | - run: make 18 | - run: file ./bin/phantomjs 19 | - run: ./bin/phantomjs --version 20 | - run: make check 21 | 22 | -------------------------------------------------------------------------------- /.github/workflows/amd64_windows_clang.yml: -------------------------------------------------------------------------------- 1 | name: amd64_windows_clang 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | amd64_windows_clang: 8 | runs-on: windows-2019 9 | env: 10 | CC: clang 11 | CXX: clang++ 12 | steps: 13 | - uses: actions/checkout@v2 14 | - run: echo "::add-path::C:\\msys64\\usr\\bin" 15 | - run: pacman --version 16 | - run: pacman -Sy 17 | - run: pacman --noconfirm -S pacman-mirrors 18 | - name: 'Install requirements' 19 | run: pacman --noconfirm -S mingw64/mingw-w64-x86_64-clang mingw64/mingw-w64-x86_64-cmake mingw64/mingw-w64-x86_64-qtwebkit mingw64/mingw-w64-x86_64-python2 20 | - run: echo "::add-path::C:\\msys64\\mingw64\\bin" 21 | - run: clang++ --version && cmake --version && qmake --version 22 | name: 'Display tools version' 23 | - run: bash ./configure 24 | name: './configure' 25 | env: 26 | CMAKE_CMD: 'cmake -G "MinGW Makefiles"' 27 | - run: mingw32-make 28 | name: 'make' 29 | - run: file ./bin/phantomjs 30 | - run: ldd ./bin/phantomjs 31 | - run: ./bin/phantomjs --version 32 | -------------------------------------------------------------------------------- /.github/workflows/amd64_windows_gcc.yml: -------------------------------------------------------------------------------- 1 | name: amd64_windows_gcc 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | amd64_windows_gcc: 8 | runs-on: windows-2019 9 | env: 10 | CC: gcc 11 | steps: 12 | - uses: actions/checkout@v2 13 | - run: echo "::add-path::C:\\msys64\\usr\\bin" 14 | - run: pacman --version 15 | - run: pacman -Sy 16 | - run: pacman --noconfirm -S pacman-mirrors 17 | - name: 'Install requirements' 18 | run: pacman --noconfirm -S mingw64/mingw-w64-x86_64-toolchain mingw64/mingw-w64-x86_64-cmake mingw64/mingw-w64-x86_64-qtwebkit mingw64/mingw-w64-x86_64-python2 19 | - run: echo "::add-path::C:\\msys64\\mingw64\\bin" 20 | - run: g++ --version && cmake --version && qmake --version 21 | name: 'Display tools version' 22 | - run: bash ./configure 23 | name: './configure' 24 | env: 25 | CMAKE_CMD: 'cmake -G "MinGW Makefiles"' 26 | - run: mingw32-make 27 | name: 'make' 28 | - run: file ./bin/phantomjs 29 | - run: ldd ./bin/phantomjs 30 | - run: ./bin/phantomjs --version 31 | -------------------------------------------------------------------------------- /.github/workflows/codestyle.yml: -------------------------------------------------------------------------------- 1 | name: Code style 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | codestyle: 8 | runs-on: ubuntu-18.04 9 | steps: 10 | - uses: actions/checkout@v2 11 | - run: sudo apt install -y clang-format-6.0 12 | name: Install clang-format 13 | - run: clang-format-6.0 --version 14 | - run: bash ./tools/format-code.sh 15 | name: Run code formatter 16 | - run: git diff 17 | - run: git diff --quiet HEAD 18 | name: Check if the styling guide is followed 19 | -------------------------------------------------------------------------------- /.github/workflows/i686_windows_gcc.yml: -------------------------------------------------------------------------------- 1 | name: i686_windows_gcc 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | i686_windows_gcc: 8 | runs-on: windows-2019 9 | env: 10 | CC: i686-w64-mingw32-gcc 11 | steps: 12 | - uses: actions/checkout@v2 13 | - run: echo "::add-path::C:\\msys64\\usr\\bin" 14 | - run: pacman --version 15 | - run: pacman -Sy 16 | - run: pacman --noconfirm -S pacman-mirrors 17 | - name: 'Install requirements' 18 | run: pacman --noconfirm -S mingw-w64-cross-toolchain mingw32/mingw-w64-i686-cmake mingw32/mingw-w64-i686-qtwebkit mingw32/mingw-w64-i686-python2 19 | - run: echo "::add-path::C:\\msys64\\mingw32\\bin" 20 | - run: i686-w64-mingw32-gcc --version && cmake --version && qmake --version 21 | name: 'Display tools version' 22 | - run: bash ./configure 23 | name: './configure' 24 | env: 25 | CMAKE_CMD: 'cmake -G "MinGW Makefiles"' 26 | - run: mingw32-make 27 | name: 'make' 28 | - run: file ./bin/phantomjs 29 | - run: ldd ./bin/phantomjs 30 | - run: ./bin/phantomjs --version 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pro.user* 3 | *.xcodeproj 4 | Makefile* 5 | *~ 6 | *.moc 7 | moc_* 8 | qrc_* 9 | .qmake.stash 10 | *.o 11 | *.swp 12 | *.pyc 13 | *.a 14 | /debian/*.debhelper 15 | /debian/files 16 | /debian/*.log 17 | /debian/*.substvars 18 | /debian/*/ 19 | /deploy/qt-*.tar.gz 20 | /deploy/Qt-* 21 | /symbols 22 | /src/qt/qtc-debugging-helper 23 | /src/phantomjs_plugin_import.cpp 24 | 25 | # ignore ctags 26 | /tags 27 | /tools/dump_syms.app/ 28 | 29 | # Ignore Visual Studio temporary files, build results, etc 30 | *.suo 31 | *.user 32 | *.sln.docstates 33 | *_i.c 34 | *_p.c 35 | *.ilk 36 | *.meta 37 | *.obj 38 | *.pch 39 | *.pdb 40 | *.pgc 41 | *.pgd 42 | *.rsp 43 | *.sbr 44 | *.tlb 45 | *.tli 46 | *.tlh 47 | *.tmp 48 | *.log 49 | *.sdf 50 | *.vcxproj 51 | *.vcxproj.filters 52 | *.lib 53 | *.prl 54 | *.intermediate.manifest 55 | 56 | # Build results 57 | [Dd]ebug*/ 58 | [Rr]elease/ 59 | bin/ 60 | *.class 61 | build/ 62 | .gradle/ 63 | 64 | # CMake 65 | CMakeLists.txt.user 66 | CMakeCache.txt 67 | CMakeFiles 68 | CMakeScripts 69 | Testing 70 | Makefile 71 | cmake_install.cmake 72 | install_manifest.txt 73 | compile_commands.json 74 | CTestTestfile.cmake 75 | _deps 76 | *_autogen 77 | 78 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.0) 2 | project(phantomjs) 3 | 4 | set (CMAKE_CXX_STANDARD 11) 5 | 6 | find_package(Qt5 COMPONENTS Core Network WebKitWidgets REQUIRED) 7 | find_package(Threads REQUIRED) 8 | 9 | message("Using Qt version ${Qt5Core_VERSION}") 10 | if (Qt5Core_VERSION VERSION_LESS 5.5.0) 11 | message(FATAL_ERROR "This version of Qt is not supported. Please use Qt 5.5 or later") 12 | endif() 13 | 14 | set(CMAKE_AUTOMOC ON) 15 | set(CMAKE_AUTORCC ON) 16 | 17 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 18 | 19 | file(GLOB_RECURSE PHANTOMJS_SOURCES src/*.cpp) 20 | include_directories(src) 21 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 22 | 23 | set(THIRDPARTY_SOURCES src/mongoose/mongoose.c src/qcommandline/qcommandline.cpp src/linenoise/src/linenoise.c) 24 | include_directories(src/linenoise/src) 25 | include_directories(src/mongoose) 26 | include_directories(src/qcommandline) 27 | 28 | if (WIN32) 29 | set(EXTRA_LIBS ws2_32) 30 | add_definitions(-DQCOMMANDLINE_STATIC) 31 | else() 32 | set(EXTRA_LIBS dl) 33 | endif() 34 | 35 | add_executable(${PROJECT_NAME} src/phantomjs.qrc ${PHANTOMJS_SOURCES} ${THIRDPARTY_SOURCES}) 36 | target_link_libraries(${PROJECT_NAME} ${EXTRA_LIBS} Qt5::Core Qt5::Network Qt5::WebKitWidgets Threads::Threads) 37 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 38 | 39 | add_custom_target(check COMMAND python test/run-tests.py -v) 40 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | System requirements: 5 | 6 | * C++ toolchain such as g++ 7 or later 7 | * CMake version 3.5 or later 8 | * Qt 5 toolkit 9 | * Community QtWebKit version 5.212 or later 10 | * Python 2.7 (to run the tests) 11 | 12 | 13 | Installation on Linux 14 | --------------------- 15 | 16 | Due to the required QtWebKit >= 5.212, only the following distributions will 17 | be supported: 18 | 19 | * Debian 10 (buster) or later 20 | * Ubuntu 18.04 (bionic) or later 21 | * Fedora 28 or later 22 | 23 | On Debian/Ubuntu, the requirements can be fulfilled by installing these packages: 24 | 25 | sudo apt install g++ cmake qt5-default libqt5webkit5-dev python 26 | 27 | After unpacking the source tarball or cloning the repository: 28 | 29 | ./configure && make 30 | 31 | Do a quick sanity check: 32 | 33 | ./bin/phantomjs --version 34 | 35 | Run the test suite: 36 | 37 | make check 38 | 39 | Install it (may require sudo): 40 | 41 | make install 42 | 43 | 44 | Installation on Windows 45 | ----------------------- 46 | 47 | Only MinGW is supported for now. 48 | 49 | First, install MSYS2. 50 | 51 | Then, from "MYS2 MinGW64 32-bit" shell, install the required packages: 52 | 53 | pacman -S msys/make 54 | pacman -S mingw32/mingw-w64-i686-toolchain 55 | pacman -S mingw32/mingw-w64-i686-cmake 56 | pacman -S mingw32/mingw-w64-i686-qtwebkit 57 | pacman -S mingw32/mingw-w64-i686-python2 58 | 59 | Note: add --disable-download-timeout as an additional argument, if the 60 | installation failed due to the slow server responses. 61 | 62 | After unpacking the source tarball or cloning the repository: 63 | 64 | cmake . -G "MinGW Makefiles" 65 | 66 | And then start the build process: 67 | 68 | make 69 | 70 | Do a quick sanity check: 71 | 72 | ./bin/phantomjs.exe --version 73 | 74 | 75 | Installation on macOS 76 | --------------------- 77 | 78 | To be written. 79 | 80 | -------------------------------------------------------------------------------- /LICENSE.BSD: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions are met: 3 | 4 | * Redistributions of source code must retain the above copyright 5 | notice, this list of conditions and the following disclaimer. 6 | * Redistributions in binary form must reproduce the above copyright 7 | notice, this list of conditions and the following disclaimer in the 8 | documentation and/or other materials provided with the distribution. 9 | * Neither the name of the nor the 10 | names of its contributors may be used to endorse or promote products 11 | derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 17 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [PhantomJS](http://phantomjs.org) - Scriptable Headless WebKit 2 | 3 | PhantomJS ([phantomjs.org](http://phantomjs.org)) is a headless WebKit scriptable with JavaScript. The latest [stable release](http://phantomjs.org/release-2.1.html) is version 2.1. 4 | 5 | **Important**: PhantomJS development is suspended until further notice (see [#15344](https://github.com/ariya/phantomjs/issues/15344) for more details). 6 | 7 | ## Use Cases 8 | 9 | - **Headless web testing**. Lightning-fast testing without the browser is now possible! 10 | - **Page automation**. [Access and manipulate](http://phantomjs.org/page-automation.html) web pages with the standard DOM API, or with usual libraries like jQuery. 11 | - **Screen capture**. Programmatically [capture web contents](http://phantomjs.org/screen-capture.html), including CSS, SVG and Canvas. Build server-side web graphics apps, from a screenshot service to a vector chart rasterizer. 12 | - **Network monitoring**. Automate performance analysis, track [page loading](http://phantomjs.org/network-monitoring.html) and export as standard HAR format. 13 | 14 | ## Features 15 | 16 | - **Multiplatform**, available on major operating systems: Windows, Mac OS X, Linux, and other Unices. 17 | - **Fast and native implementation** of web standards: DOM, CSS, JavaScript, Canvas, and SVG. No emulation! 18 | - **Pure headless (no X11) on Linux**, ideal for continuous integration systems. Also runs on Amazon EC2, Heroku, and Iron.io. 19 | - **Easy to install**: [Download](http://phantomjs.org/download.html), unpack, and start having fun in just 5 minutes. 20 | 21 | ## Questions? 22 | 23 | - Explore the complete [documentation](http://phantomjs.org/documentation/). 24 | - Read tons of [user articles](http://phantomjs.org/buzz.html) on using PhantomJS. 25 | - Join the [mailing-list](http://groups.google.com/group/phantomjs) and discuss with other PhantomJS fans. 26 | 27 | PhantomJS is free software/open source, and is distributed under the [BSD license](http://opensource.org/licenses/BSD-3-Clause). It contains third-party code, see the included `third-party.txt` file for the license information on third-party code. 28 | 29 | PhantomJS is created and maintained by [@ariyahidayat](http://twitter.com/AriyaHidayat), with the help of [many contributors](https://github.com/ariya/phantomjs/contributors). -------------------------------------------------------------------------------- /examples/arguments.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var system = require('system'); 3 | if (system.args.length === 1) { 4 | console.log('Try to pass some args when invoking this script!'); 5 | } else { 6 | system.args.forEach(function (arg, i) { 7 | console.log(i + ': ' + arg); 8 | }); 9 | } 10 | phantom.exit(); 11 | -------------------------------------------------------------------------------- /examples/child_process-examples.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var spawn = require("child_process").spawn 3 | var execFile = require("child_process").execFile 4 | 5 | var child = spawn("ls", ["-lF", "/rooot"]) 6 | 7 | child.stdout.on("data", function (data) { 8 | console.log("spawnSTDOUT:", JSON.stringify(data)) 9 | }) 10 | 11 | child.stderr.on("data", function (data) { 12 | console.log("spawnSTDERR:", JSON.stringify(data)) 13 | }) 14 | 15 | child.on("exit", function (code) { 16 | console.log("spawnEXIT:", code) 17 | }) 18 | 19 | //child.kill("SIGKILL") 20 | 21 | execFile("ls", ["-lF", "/usr"], null, function (err, stdout, stderr) { 22 | console.log("execFileSTDOUT:", JSON.stringify(stdout)) 23 | console.log("execFileSTDERR:", JSON.stringify(stderr)) 24 | }) 25 | 26 | setTimeout(function () { 27 | phantom.exit(0) 28 | }, 2000) 29 | -------------------------------------------------------------------------------- /examples/colorwheel.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var page = require('webpage').create(); 3 | page.viewportSize = { width: 400, height : 400 }; 4 | page.content = ''; 5 | page.evaluate(function() { 6 | var el = document.getElementById('surface'), 7 | context = el.getContext('2d'), 8 | width = window.innerWidth, 9 | height = window.innerHeight, 10 | cx = width / 2, 11 | cy = height / 2, 12 | radius = width / 2.3, 13 | imageData, 14 | pixels, 15 | hue, sat, value, 16 | i = 0, x, y, rx, ry, d, 17 | f, g, p, u, v, w, rgb; 18 | 19 | el.width = width; 20 | el.height = height; 21 | imageData = context.createImageData(width, height); 22 | pixels = imageData.data; 23 | 24 | for (y = 0; y < height; y = y + 1) { 25 | for (x = 0; x < width; x = x + 1, i = i + 4) { 26 | rx = x - cx; 27 | ry = y - cy; 28 | d = rx * rx + ry * ry; 29 | if (d < radius * radius) { 30 | hue = 6 * (Math.atan2(ry, rx) + Math.PI) / (2 * Math.PI); 31 | sat = Math.sqrt(d) / radius; 32 | g = Math.floor(hue); 33 | f = hue - g; 34 | u = 255 * (1 - sat); 35 | v = 255 * (1 - sat * f); 36 | w = 255 * (1 - sat * (1 - f)); 37 | pixels[i] = [255, v, u, u, w, 255, 255][g]; 38 | pixels[i + 1] = [w, 255, 255, v, u, u, w][g]; 39 | pixels[i + 2] = [u, u, w, 255, 255, v, u][g]; 40 | pixels[i + 3] = 255; 41 | } 42 | } 43 | } 44 | 45 | context.putImageData(imageData, 0, 0); 46 | document.body.style.backgroundColor = 'white'; 47 | document.body.style.margin = '0px'; 48 | }); 49 | 50 | page.render('colorwheel.png'); 51 | 52 | phantom.exit(); 53 | -------------------------------------------------------------------------------- /examples/countdown.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var t = 10, 3 | interval = setInterval(function(){ 4 | if ( t > 0 ) { 5 | console.log(t--); 6 | } else { 7 | console.log("BLAST OFF!"); 8 | phantom.exit(); 9 | } 10 | }, 1000); 11 | -------------------------------------------------------------------------------- /examples/detectsniff.js: -------------------------------------------------------------------------------- 1 | // Detect if a web page sniffs the user agent or not. 2 | 3 | "use strict"; 4 | var page = require('webpage').create(), 5 | system = require('system'), 6 | sniffed, 7 | address; 8 | 9 | page.onInitialized = function () { 10 | page.evaluate(function () { 11 | 12 | (function () { 13 | var userAgent = window.navigator.userAgent, 14 | platform = window.navigator.platform; 15 | 16 | window.navigator = { 17 | appCodeName: 'Mozilla', 18 | appName: 'Netscape', 19 | cookieEnabled: false, 20 | sniffed: false 21 | }; 22 | 23 | window.navigator.__defineGetter__('userAgent', function () { 24 | window.navigator.sniffed = true; 25 | return userAgent; 26 | }); 27 | 28 | window.navigator.__defineGetter__('platform', function () { 29 | window.navigator.sniffed = true; 30 | return platform; 31 | }); 32 | })(); 33 | }); 34 | }; 35 | 36 | if (system.args.length === 1) { 37 | console.log('Usage: detectsniff.js '); 38 | phantom.exit(1); 39 | } else { 40 | address = system.args[1]; 41 | console.log('Checking ' + address + '...'); 42 | page.open(address, function (status) { 43 | if (status !== 'success') { 44 | console.log('FAIL to load the address'); 45 | phantom.exit(); 46 | } else { 47 | window.setTimeout(function () { 48 | sniffed = page.evaluate(function () { 49 | return navigator.sniffed; 50 | }); 51 | if (sniffed) { 52 | console.log('The page tried to sniff the user agent.'); 53 | } else { 54 | console.log('The page did not try to sniff the user agent.'); 55 | } 56 | phantom.exit(); 57 | }, 1500); 58 | } 59 | }); 60 | } 61 | -------------------------------------------------------------------------------- /examples/echoToFile.js: -------------------------------------------------------------------------------- 1 | // echoToFile.js - Write in a given file all the parameters passed on the CLI 2 | "use strict"; 3 | var fs = require('fs'), 4 | system = require('system'); 5 | 6 | if (system.args.length < 3) { 7 | console.log("Usage: echoToFile.js DESTINATION_FILE "); 8 | phantom.exit(1); 9 | } else { 10 | var content = '', 11 | f = null, 12 | i; 13 | for ( i= 2; i < system.args.length; ++i ) { 14 | content += system.args[i] + (i === system.args.length-1 ? '' : ' '); 15 | } 16 | 17 | try { 18 | fs.write(system.args[1], content, 'w'); 19 | } catch(e) { 20 | console.log(e); 21 | } 22 | 23 | phantom.exit(); 24 | } 25 | -------------------------------------------------------------------------------- /examples/features.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var feature, supported = [], unsupported = []; 3 | 4 | phantom.injectJs('modernizr.js'); 5 | console.log('Detected features (using Modernizr ' + Modernizr._version + '):'); 6 | for (feature in Modernizr) { 7 | if (Modernizr.hasOwnProperty(feature)) { 8 | if (feature[0] !== '_' && typeof Modernizr[feature] !== 'function' && 9 | feature !== 'input' && feature !== 'inputtypes') { 10 | if (Modernizr[feature]) { 11 | supported.push(feature); 12 | } else { 13 | unsupported.push(feature); 14 | } 15 | } 16 | } 17 | } 18 | 19 | console.log(''); 20 | console.log('Supported:'); 21 | supported.forEach(function (e) { 22 | console.log(' ' + e); 23 | }); 24 | 25 | console.log(''); 26 | console.log('Not supported:'); 27 | unsupported.forEach(function (e) { 28 | console.log(' ' + e); 29 | }); 30 | phantom.exit(); 31 | -------------------------------------------------------------------------------- /examples/fibo.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var fibs = [0, 1]; 3 | var ticker = window.setInterval(function () { 4 | console.log(fibs[fibs.length - 1]); 5 | fibs.push(fibs[fibs.length - 1] + fibs[fibs.length - 2]); 6 | if (fibs.length > 10) { 7 | window.clearInterval(ticker); 8 | phantom.exit(); 9 | } 10 | }, 300); 11 | -------------------------------------------------------------------------------- /examples/hello.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | console.log('Hello, world!'); 3 | phantom.exit(); 4 | -------------------------------------------------------------------------------- /examples/injectme.js: -------------------------------------------------------------------------------- 1 | // Use 'page.injectJs()' to load the script itself in the Page context 2 | 3 | "use strict"; 4 | if ( typeof(phantom) !== "undefined" ) { 5 | var page = require('webpage').create(); 6 | 7 | // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") 8 | page.onConsoleMessage = function(msg) { 9 | console.log(msg); 10 | }; 11 | 12 | page.onAlert = function(msg) { 13 | console.log(msg); 14 | }; 15 | 16 | console.log("* Script running in the Phantom context."); 17 | console.log("* Script will 'inject' itself in a page..."); 18 | page.open("about:blank", function(status) { 19 | if ( status === "success" ) { 20 | console.log(page.injectJs("injectme.js") ? "... done injecting itself!" : "... fail! Check the $PWD?!"); 21 | } 22 | phantom.exit(); 23 | }); 24 | } else { 25 | alert("* Script running in the Page context."); 26 | } 27 | -------------------------------------------------------------------------------- /examples/loadspeed.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var page = require('webpage').create(), 3 | system = require('system'), 4 | t, address; 5 | 6 | if (system.args.length === 1) { 7 | console.log('Usage: loadspeed.js '); 8 | phantom.exit(1); 9 | } else { 10 | t = Date.now(); 11 | address = system.args[1]; 12 | page.open(address, function (status) { 13 | if (status !== 'success') { 14 | console.log('FAIL to load the address'); 15 | } else { 16 | t = Date.now() - t; 17 | console.log('Page title is ' + page.evaluate(function () { 18 | return document.title; 19 | })); 20 | console.log('Loading time ' + t + ' msec'); 21 | } 22 | phantom.exit(); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /examples/loadurlwithoutcss.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var page = require('webpage').create(), 3 | system = require('system'); 4 | 5 | if (system.args.length < 2) { 6 | console.log('Usage: loadurlwithoutcss.js URL'); 7 | phantom.exit(); 8 | } 9 | 10 | var address = system.args[1]; 11 | 12 | page.onResourceRequested = function(requestData, request) { 13 | if ((/http:\/\/.+?\.css/gi).test(requestData['url']) || requestData.headers['Content-Type'] == 'text/css') { 14 | console.log('The url of the request is matching. Aborting: ' + requestData['url']); 15 | request.abort(); 16 | } 17 | }; 18 | 19 | page.open(address, function(status) { 20 | if (status === 'success') { 21 | phantom.exit(); 22 | } else { 23 | console.log('Unable to load the address!'); 24 | phantom.exit(); 25 | } 26 | }); -------------------------------------------------------------------------------- /examples/module.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var universe = require('./universe'); 3 | universe.start(); 4 | console.log('The answer is ' + universe.answer); 5 | phantom.exit(); 6 | -------------------------------------------------------------------------------- /examples/netlog.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var page = require('webpage').create(), 3 | system = require('system'), 4 | address; 5 | 6 | if (system.args.length === 1) { 7 | console.log('Usage: netlog.js '); 8 | phantom.exit(1); 9 | } else { 10 | address = system.args[1]; 11 | 12 | page.onResourceRequested = function (req) { 13 | console.log('requested: ' + JSON.stringify(req, undefined, 4)); 14 | }; 15 | 16 | page.onResourceReceived = function (res) { 17 | console.log('received: ' + JSON.stringify(res, undefined, 4)); 18 | }; 19 | 20 | page.open(address, function (status) { 21 | if (status !== 'success') { 22 | console.log('FAIL to load the address'); 23 | } 24 | phantom.exit(); 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /examples/openurlwithproxy.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var page = require('webpage').create(), 3 | system = require('system'), 4 | host, port, address; 5 | 6 | if (system.args.length < 4) { 7 | console.log('Usage: openurlwithproxy.js '); 8 | phantom.exit(1); 9 | } else { 10 | host = system.args[1]; 11 | port = system.args[2]; 12 | address = system.args[3]; 13 | phantom.setProxy(host, port, 'manual', '', ''); 14 | page.open(address, function (status) { 15 | if (status !== 'success') { 16 | console.log('FAIL to load the address "' + 17 | address + '" using proxy "' + host + ':' + port + '"'); 18 | } else { 19 | console.log('Page title is ' + page.evaluate(function () { 20 | return document.title; 21 | })); 22 | } 23 | phantom.exit(); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /examples/outputEncoding.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function helloWorld() { 3 | console.log(phantom.outputEncoding + ": こんにちは、世界!"); 4 | } 5 | 6 | console.log("Using default encoding..."); 7 | helloWorld(); 8 | 9 | console.log("\nUsing other encodings..."); 10 | 11 | var encodings = ["euc-jp", "sjis", "utf8", "System"]; 12 | for (var i = 0; i < encodings.length; i++) { 13 | phantom.outputEncoding = encodings[i]; 14 | helloWorld(); 15 | } 16 | 17 | phantom.exit() 18 | -------------------------------------------------------------------------------- /examples/pagecallback.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var p = require("webpage").create(); 3 | 4 | p.onConsoleMessage = function(msg) { console.log(msg); }; 5 | 6 | // Calls to "callPhantom" within the page 'p' arrive here 7 | p.onCallback = function(msg) { 8 | console.log("Received by the 'phantom' main context: "+msg); 9 | return "Hello there, I'm coming to you from the 'phantom' context instead"; 10 | }; 11 | 12 | p.evaluate(function() { 13 | // Return-value of the "onCallback" handler arrive here 14 | var callbackResponse = window.callPhantom("Hello, I'm coming to you from the 'page' context"); 15 | console.log("Received by the 'page' context: "+callbackResponse); 16 | }); 17 | 18 | phantom.exit(); 19 | -------------------------------------------------------------------------------- /examples/phantomwebintro.js: -------------------------------------------------------------------------------- 1 | // Read the Phantom webpage '#intro' element text using jQuery and "includeJs" 2 | 3 | "use strict"; 4 | var page = require('webpage').create(); 5 | 6 | page.onConsoleMessage = function(msg) { 7 | console.log(msg); 8 | }; 9 | 10 | page.open("http://phantomjs.org/", function(status) { 11 | if (status === "success") { 12 | page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() { 13 | page.evaluate(function() { 14 | console.log("$(\".explanation\").text() -> " + $(".explanation").text()); 15 | }); 16 | phantom.exit(0); 17 | }); 18 | } else { 19 | phantom.exit(1); 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /examples/post.js: -------------------------------------------------------------------------------- 1 | // Example using HTTP POST operation 2 | 3 | "use strict"; 4 | var page = require('webpage').create(), 5 | server = 'http://ptsv2.com/t/phantomjs-toilet/post', 6 | data = 'universe=expanding&answer=42'; 7 | 8 | page.open(server, 'post', data, function (status) { 9 | if (status !== 'success') { 10 | console.log('Unable to post!'); 11 | } else { 12 | console.log(page.content); 13 | } 14 | phantom.exit(); 15 | }); 16 | -------------------------------------------------------------------------------- /examples/postjson.js: -------------------------------------------------------------------------------- 1 | // Example using HTTP POST operation 2 | 3 | "use strict"; 4 | var page = require('webpage').create(), 5 | server = 'http://ptsv2.com/t/phantomjs-toilet/post', 6 | data = '{"universe": "expanding", "answer": 42}'; 7 | 8 | var headers = { 9 | "Content-Type": "application/json" 10 | } 11 | 12 | page.open(server, 'post', data, headers, function (status) { 13 | if (status !== 'success') { 14 | console.log('Unable to post!'); 15 | } else { 16 | console.log(page.content); 17 | } 18 | phantom.exit(); 19 | }); 20 | -------------------------------------------------------------------------------- /examples/postserver.js: -------------------------------------------------------------------------------- 1 | // Example using HTTP POST operation 2 | 3 | "use strict"; 4 | var page = require('webpage').create(), 5 | server = require('webserver').create(), 6 | system = require('system'), 7 | data = 'universe=expanding&answer=42'; 8 | 9 | if (system.args.length !== 2) { 10 | console.log('Usage: postserver.js '); 11 | phantom.exit(1); 12 | } 13 | 14 | var port = system.args[1]; 15 | 16 | var service = server.listen(port, function (request, response) { 17 | console.log('Request received at ' + new Date()); 18 | 19 | response.statusCode = 200; 20 | response.headers = { 21 | 'Cache': 'no-cache', 22 | 'Content-Type': 'text/plain;charset=utf-8' 23 | }; 24 | response.write(JSON.stringify(request, null, 4)); 25 | response.close(); 26 | }); 27 | 28 | page.open('http://localhost:' + port + '/', 'post', data, function (status) { 29 | if (status !== 'success') { 30 | console.log('Unable to post!'); 31 | } else { 32 | console.log(page.plainText); 33 | } 34 | phantom.exit(); 35 | }); 36 | -------------------------------------------------------------------------------- /examples/printenv.js: -------------------------------------------------------------------------------- 1 | var system = require('system'), 2 | env = system.env, 3 | key; 4 | 5 | for (key in env) { 6 | if (env.hasOwnProperty(key)) { 7 | console.log(key + '=' + env[key]); 8 | } 9 | } 10 | phantom.exit(); 11 | -------------------------------------------------------------------------------- /examples/printmargins.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var page = require('webpage').create(), 3 | system = require('system'); 4 | 5 | if (system.args.length < 7) { 6 | console.log('Usage: printmargins.js URL filename LEFT TOP RIGHT BOTTOM'); 7 | console.log(' margin examples: "1cm", "10px", "7mm", "5in"'); 8 | phantom.exit(1); 9 | } else { 10 | var address = system.args[1]; 11 | var output = system.args[2]; 12 | var marginLeft = system.args[3]; 13 | var marginTop = system.args[4]; 14 | var marginRight = system.args[5]; 15 | var marginBottom = system.args[6]; 16 | page.viewportSize = { width: 600, height: 600 }; 17 | page.paperSize = { 18 | format: 'A4', 19 | margin: { 20 | left: marginLeft, 21 | top: marginTop, 22 | right: marginRight, 23 | bottom: marginBottom 24 | } 25 | }; 26 | page.open(address, function (status) { 27 | if (status !== 'success') { 28 | console.log('Unable to load the address!'); 29 | } else { 30 | window.setTimeout(function () { 31 | page.render(output); 32 | phantom.exit(); 33 | }, 200); 34 | } 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /examples/rasterize.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var page = require('webpage').create(), 3 | system = require('system'), 4 | address, output, size, pageWidth, pageHeight; 5 | 6 | if (system.args.length < 3 || system.args.length > 5) { 7 | console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]'); 8 | console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"'); 9 | console.log(' image (png/jpg output) examples: "1920px" entire page, window width 1920px'); 10 | console.log(' "800px*600px" window, clipped to 800x600'); 11 | phantom.exit(1); 12 | } else { 13 | address = system.args[1]; 14 | output = system.args[2]; 15 | page.viewportSize = { width: 600, height: 600 }; 16 | if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") { 17 | size = system.args[3].split('*'); 18 | page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' } 19 | : { format: system.args[3], orientation: 'portrait', margin: '1cm' }; 20 | } else if (system.args.length > 3 && system.args[3].substr(-2) === "px") { 21 | size = system.args[3].split('*'); 22 | if (size.length === 2) { 23 | pageWidth = parseInt(size[0], 10); 24 | pageHeight = parseInt(size[1], 10); 25 | page.viewportSize = { width: pageWidth, height: pageHeight }; 26 | page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight }; 27 | } else { 28 | console.log("size:", system.args[3]); 29 | pageWidth = parseInt(system.args[3], 10); 30 | pageHeight = parseInt(pageWidth * 3/4, 10); // it's as good an assumption as any 31 | console.log ("pageHeight:",pageHeight); 32 | page.viewportSize = { width: pageWidth, height: pageHeight }; 33 | } 34 | } 35 | if (system.args.length > 4) { 36 | page.zoomFactor = system.args[4]; 37 | } 38 | page.open(address, function (status) { 39 | if (status !== 'success') { 40 | console.log('Unable to load the address!'); 41 | phantom.exit(1); 42 | } else { 43 | window.setTimeout(function () { 44 | page.render(output); 45 | phantom.exit(); 46 | }, 200); 47 | } 48 | }); 49 | } 50 | -------------------------------------------------------------------------------- /examples/render_multi_url.js: -------------------------------------------------------------------------------- 1 | // Render Multiple URLs to file 2 | 3 | "use strict"; 4 | var RenderUrlsToFile, arrayOfUrls, system; 5 | 6 | system = require("system"); 7 | 8 | /* 9 | Render given urls 10 | @param array of URLs to render 11 | @param callbackPerUrl Function called after finishing each URL, including the last URL 12 | @param callbackFinal Function called after finishing everything 13 | */ 14 | RenderUrlsToFile = function(urls, callbackPerUrl, callbackFinal) { 15 | var getFilename, next, page, retrieve, urlIndex, webpage; 16 | urlIndex = 0; 17 | webpage = require("webpage"); 18 | page = null; 19 | getFilename = function() { 20 | return "rendermulti-" + urlIndex + ".png"; 21 | }; 22 | next = function(status, url, file) { 23 | page.close(); 24 | callbackPerUrl(status, url, file); 25 | return retrieve(); 26 | }; 27 | retrieve = function() { 28 | var url; 29 | if (urls.length > 0) { 30 | url = urls.shift(); 31 | urlIndex++; 32 | page = webpage.create(); 33 | page.viewportSize = { 34 | width: 800, 35 | height: 600 36 | }; 37 | page.settings.userAgent = "Phantom.js bot"; 38 | return page.open("http://" + url, function(status) { 39 | var file; 40 | file = getFilename(); 41 | if (status === "success") { 42 | return window.setTimeout((function() { 43 | page.render(file); 44 | return next(status, url, file); 45 | }), 200); 46 | } else { 47 | return next(status, url, file); 48 | } 49 | }); 50 | } else { 51 | return callbackFinal(); 52 | } 53 | }; 54 | return retrieve(); 55 | }; 56 | 57 | arrayOfUrls = null; 58 | 59 | if (system.args.length > 1) { 60 | arrayOfUrls = Array.prototype.slice.call(system.args, 1); 61 | } else { 62 | console.log("Usage: phantomjs render_multi_url.js [domain.name1, domain.name2, ...]"); 63 | arrayOfUrls = ["www.google.com", "www.bbc.co.uk", "phantomjs.org"]; 64 | } 65 | 66 | RenderUrlsToFile(arrayOfUrls, (function(status, url, file) { 67 | if (status !== "success") { 68 | return console.log("Unable to render '" + url + "'"); 69 | } else { 70 | return console.log("Rendered '" + url + "' at '" + file + "'"); 71 | } 72 | }), function() { 73 | return phantom.exit(); 74 | }); 75 | -------------------------------------------------------------------------------- /examples/scandir.js: -------------------------------------------------------------------------------- 1 | // List all the files in a Tree of Directories 2 | 3 | "use strict"; 4 | var system = require('system'); 5 | 6 | if (system.args.length !== 2) { 7 | console.log("Usage: phantomjs scandir.js DIRECTORY_TO_SCAN"); 8 | phantom.exit(1); 9 | } 10 | 11 | var scanDirectory = function (path) { 12 | var fs = require('fs'); 13 | if (fs.exists(path) && fs.isFile(path)) { 14 | console.log(path); 15 | } else if (fs.isDirectory(path)) { 16 | fs.list(path).forEach(function (e) { 17 | if ( e !== "." && e !== ".." ) { //< Avoid loops 18 | scanDirectory(path + '/' + e); 19 | } 20 | }); 21 | } 22 | }; 23 | scanDirectory(system.args[1]); 24 | phantom.exit(); 25 | -------------------------------------------------------------------------------- /examples/server.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var page = require('webpage').create(); 3 | var server = require('webserver').create(); 4 | var system = require('system'); 5 | var host, port; 6 | 7 | if (system.args.length !== 2) { 8 | console.log('Usage: server.js '); 9 | phantom.exit(1); 10 | } else { 11 | port = system.args[1]; 12 | var listening = server.listen(port, function (request, response) { 13 | console.log("GOT HTTP REQUEST"); 14 | console.log(JSON.stringify(request, null, 4)); 15 | 16 | // we set the headers here 17 | response.statusCode = 200; 18 | response.headers = {"Cache": "no-cache", "Content-Type": "text/html"}; 19 | // this is also possible: 20 | response.setHeader("foo", "bar"); 21 | // now we write the body 22 | // note: the headers above will now be sent implictly 23 | response.write("YES!"); 24 | // note: writeBody can be called multiple times 25 | response.write("

pretty cool :)"); 26 | response.close(); 27 | }); 28 | if (!listening) { 29 | console.log("could not create web server listening on port " + port); 30 | phantom.exit(); 31 | } 32 | var url = "http://localhost:" + port + "/foo/bar.php?asdf=true"; 33 | console.log("SENDING REQUEST TO:"); 34 | console.log(url); 35 | page.open(url, function (status) { 36 | if (status !== 'success') { 37 | console.log('FAIL to load the address'); 38 | } else { 39 | console.log("GOT REPLY FROM SERVER:"); 40 | console.log(page.content); 41 | } 42 | phantom.exit(); 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /examples/serverkeepalive.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var port, server, service, 3 | system = require('system'); 4 | 5 | if (system.args.length !== 2) { 6 | console.log('Usage: serverkeepalive.js '); 7 | phantom.exit(1); 8 | } else { 9 | port = system.args[1]; 10 | server = require('webserver').create(); 11 | 12 | service = server.listen(port, { keepAlive: true }, function (request, response) { 13 | console.log('Request at ' + new Date()); 14 | console.log(JSON.stringify(request, null, 4)); 15 | 16 | var body = JSON.stringify(request, null, 4); 17 | response.statusCode = 200; 18 | response.headers = { 19 | 'Cache': 'no-cache', 20 | 'Content-Type': 'text/plain', 21 | 'Connection': 'Keep-Alive', 22 | 'Keep-Alive': 'timeout=5, max=100', 23 | 'Content-Length': body.length 24 | }; 25 | response.write(body); 26 | response.close(); 27 | }); 28 | 29 | if (service) { 30 | console.log('Web server running on port ' + port); 31 | } else { 32 | console.log('Error: Could not create web server listening on port ' + port); 33 | phantom.exit(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/simpleserver.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var port, server, service, 3 | system = require('system'); 4 | 5 | if (system.args.length !== 2) { 6 | console.log('Usage: simpleserver.js '); 7 | phantom.exit(1); 8 | } else { 9 | port = system.args[1]; 10 | server = require('webserver').create(); 11 | 12 | service = server.listen(port, function (request, response) { 13 | 14 | console.log('Request at ' + new Date()); 15 | console.log(JSON.stringify(request, null, 4)); 16 | 17 | response.statusCode = 200; 18 | response.headers = { 19 | 'Cache': 'no-cache', 20 | 'Content-Type': 'text/html' 21 | }; 22 | response.write(''); 23 | response.write(''); 24 | response.write('Hello, world!'); 25 | response.write(''); 26 | response.write(''); 27 | response.write('

This is from PhantomJS web server.

'); 28 | response.write('

Request data:

'); 29 | response.write('
');
30 |         response.write(JSON.stringify(request, null, 4));
31 |         response.write('
'); 32 | response.write(''); 33 | response.write(''); 34 | response.close(); 35 | }); 36 | 37 | if (service) { 38 | console.log('Web server running on port ' + port); 39 | } else { 40 | console.log('Error: Could not create web server listening on port ' + port); 41 | phantom.exit(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/sleepsort.js: -------------------------------------------------------------------------------- 1 | // sleepsort.js - Sort integers from the commandline in a very ridiculous way: leveraging timeouts :P 2 | 3 | "use strict"; 4 | var system = require('system'); 5 | 6 | function sleepSort(array, callback) { 7 | var sortedCount = 0, 8 | i, len; 9 | for ( i = 0, len = array.length; i < len; ++i ) { 10 | setTimeout((function(j){ 11 | return function() { 12 | console.log(array[j]); 13 | ++sortedCount; 14 | (len === sortedCount) && callback(); 15 | }; 16 | }(i)), array[i]); 17 | } 18 | } 19 | 20 | if ( system.args.length < 2 ) { 21 | console.log("Usage: phantomjs sleepsort.js PUT YOUR INTEGERS HERE SEPARATED BY SPACES"); 22 | phantom.exit(1); 23 | } else { 24 | sleepSort(system.args.slice(1), function() { 25 | phantom.exit(); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /examples/stdin-stdout-stderr.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var system = require('system'); 3 | 4 | system.stdout.write('Hello, system.stdout.write!'); 5 | system.stdout.writeLine('\nHello, system.stdout.writeLine!'); 6 | 7 | system.stderr.write('Hello, system.stderr.write!'); 8 | system.stderr.writeLine('\nHello, system.stderr.writeLine!'); 9 | 10 | system.stdout.writeLine('system.stdin.readLine(): '); 11 | var line = system.stdin.readLine(); 12 | system.stdout.writeLine(JSON.stringify(line)); 13 | 14 | // This is essentially a `readAll` 15 | system.stdout.writeLine('system.stdin.read(5): (ctrl+D to end)'); 16 | var input = system.stdin.read(5); 17 | system.stdout.writeLine(JSON.stringify(input)); 18 | 19 | phantom.exit(0); 20 | -------------------------------------------------------------------------------- /examples/universe.js: -------------------------------------------------------------------------------- 1 | // This is to be used by "module.js" (and "module.coffee") example(s). 2 | // There should NOT be a "universe.coffee" as only 1 of the 2 would 3 | // ever be loaded unless the file extension was specified. 4 | 5 | "use strict"; 6 | exports.answer = 42; 7 | 8 | exports.start = function () { 9 | console.log('Starting the universe....'); 10 | } 11 | -------------------------------------------------------------------------------- /examples/unrandomize.js: -------------------------------------------------------------------------------- 1 | // Modify global object at the page initialization. 2 | // In this example, effectively Math.random() always returns 0.42. 3 | 4 | "use strict"; 5 | var page = require('webpage').create(); 6 | 7 | page.onInitialized = function () { 8 | page.evaluate(function () { 9 | Math.random = function() { 10 | return 42 / 100; 11 | }; 12 | }); 13 | }; 14 | 15 | page.open('http://ariya.github.com/js/random/', function (status) { 16 | var result; 17 | if (status !== 'success') { 18 | console.log('Network error.'); 19 | } else { 20 | console.log(page.evaluate(function () { 21 | return document.getElementById('numbers').textContent; 22 | })); 23 | } 24 | phantom.exit(); 25 | }); 26 | -------------------------------------------------------------------------------- /examples/useragent.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var page = require('webpage').create(); 3 | console.log('The default user agent is ' + page.settings.userAgent); 4 | page.settings.userAgent = 'SpecialAgent'; 5 | page.open('http://www.httpuseragent.org', function (status) { 6 | if (status !== 'success') { 7 | console.log('Unable to access network'); 8 | } else { 9 | var ua = page.evaluate(function () { 10 | return document.getElementById('qua').value; 11 | }); 12 | console.log(ua); 13 | } 14 | phantom.exit(); 15 | }); 16 | -------------------------------------------------------------------------------- /examples/version.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | console.log('using PhantomJS version ' + 3 | phantom.version.major + '.' + 4 | phantom.version.minor + '.' + 5 | phantom.version.patch); 6 | phantom.exit(); 7 | -------------------------------------------------------------------------------- /examples/waitfor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Wait until the test condition is true or a timeout occurs. Useful for waiting 3 | * on a server response or for a ui change (fadeIn, etc.) to occur. 4 | * 5 | * @param testFx javascript condition that evaluates to a boolean, 6 | * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or 7 | * as a callback function. 8 | * @param onReady what to do when testFx condition is fulfilled, 9 | * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or 10 | * as a callback function. 11 | * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used. 12 | */ 13 | 14 | "use strict"; 15 | function waitFor(testFx, onReady, timeOutMillis) { 16 | var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s 17 | start = new Date().getTime(), 18 | condition = false, 19 | interval = setInterval(function() { 20 | if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) { 21 | // If not time-out yet and condition not yet fulfilled 22 | condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code 23 | } else { 24 | if(!condition) { 25 | // If condition still not fulfilled (timeout but condition is 'false') 26 | console.log("'waitFor()' timeout"); 27 | phantom.exit(1); 28 | } else { 29 | // Condition fulfilled (timeout and/or condition is 'true') 30 | console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms."); 31 | typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled 32 | clearInterval(interval); //< Stop this interval 33 | } 34 | } 35 | }, 250); //< repeat check every 250ms 36 | }; 37 | 38 | 39 | var page = require('webpage').create(); 40 | 41 | // Open Twitter on 'sencha' profile and, onPageLoad, do... 42 | page.open("http://twitter.com/#!/sencha", function (status) { 43 | // Check for page load success 44 | if (status !== "success") { 45 | console.log("Unable to access network"); 46 | } else { 47 | // Wait for 'signin-dropdown' to be visible 48 | waitFor(function() { 49 | // Check in the page if a specific element is now visible 50 | return page.evaluate(function() { 51 | return $("#signin-dropdown").is(":visible"); 52 | }); 53 | }, function() { 54 | console.log("The sign-in dialog should be visible now."); 55 | phantom.exit(); 56 | }); 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /src/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleExecutable 6 | phantomjs 7 | CFBundleIdentifier 8 | org.phantomjs 9 | LSUIElement 10 | 1 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/callback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhantomJS project from Ofi Labs. 3 | 4 | Copyright (C) 2012 Milian Wolff, KDAB 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | * Neither the name of the nor the 15 | names of its contributors may be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include "callback.h" 31 | 32 | #include 33 | 34 | Callback::Callback(QObject* parent) 35 | : QObject(parent) 36 | { 37 | } 38 | 39 | QVariant Callback::call(const QVariantList& arguments) 40 | { 41 | emit called(arguments); 42 | 43 | qDebug() << "Callback - call result:" << m_returnValue; 44 | return m_returnValue; 45 | } 46 | 47 | QVariant Callback::returnValue() const 48 | { 49 | return m_returnValue; 50 | } 51 | 52 | void Callback::setReturnValue(const QVariant& returnValue) 53 | { 54 | m_returnValue = returnValue; 55 | } 56 | -------------------------------------------------------------------------------- /src/callback.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhantomJS project from Ofi Labs. 3 | 4 | Copyright (C) 2012 Milian Wolff, KDAB 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | * Neither the name of the nor the 15 | names of its contributors may be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef CALLBACK_H 31 | #define CALLBACK_H 32 | 33 | #include 34 | #include 35 | 36 | class Callback : public QObject { 37 | Q_OBJECT 38 | 39 | Q_PROPERTY(QVariant returnValue READ returnValue WRITE setReturnValue) 40 | 41 | public: 42 | Callback(QObject* parent); 43 | 44 | QVariant call(const QVariantList& arguments); 45 | 46 | QVariant returnValue() const; 47 | void setReturnValue(const QVariant& returnValue); 48 | 49 | signals: 50 | void called(const QVariantList& arguments); 51 | 52 | private: 53 | QVariant m_returnValue; 54 | }; 55 | 56 | #endif // CALLBACK_H 57 | -------------------------------------------------------------------------------- /src/configurator.js: -------------------------------------------------------------------------------- 1 | (function (opts) { 2 | var i; 3 | 4 | opts = opts || {}; 5 | 6 | if (typeof opts !== 'object') { 7 | return; 8 | } 9 | 10 | for (i in opts) { 11 | if (opts.hasOwnProperty(i) && typeof opts[i] !== 'undefined') { 12 | config[i] = opts[i]; 13 | } 14 | } 15 | 16 | return null; 17 | })((%1)); 18 | -------------------------------------------------------------------------------- /src/crashdump.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhantomJS project from Ofi Labs. 3 | 4 | Copyright (C) 2011 Ariya Hidayat 5 | Copyright (C) 2011 Ivan De Marino 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | * Neither the name of the nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef CRASHDUMP_H 32 | #define CRASHDUMP_H 33 | 34 | extern void print_crash_message(); 35 | extern void init_crash_handler(); 36 | 37 | #endif // CRASHDUMP_H 38 | -------------------------------------------------------------------------------- /src/encoding.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhantomJS project from Ofi Labs. 3 | 4 | Copyright (C) 2011 Ariya Hidayat 5 | Copyright (C) 2011 execjosh, http://execjosh.blogspot.com 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | * Neither the name of the nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef ENCODING_H 32 | #define ENCODING_H 33 | 34 | #include 35 | 36 | class Encoding { 37 | public: 38 | Encoding(); 39 | Encoding(const QString& encoding); 40 | ~Encoding(); 41 | 42 | QString decode(const QByteArray& bytes) const; 43 | QByteArray encode(const QString& string) const; 44 | 45 | QString getName() const; 46 | void setEncoding(const QString& encoding); 47 | 48 | QTextCodec* getCodec() const; 49 | 50 | static const Encoding UTF8; 51 | 52 | private: 53 | QTextCodec* m_codec; 54 | static const QByteArray DEFAULT_CODEC_NAME; 55 | }; 56 | 57 | #endif // ENCODING_H 58 | -------------------------------------------------------------------------------- /src/env.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhantomJS project from Ofi Labs. 3 | 4 | Copyright (C) 2012 execjosh, http://execjosh.blogspot.com 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | * Neither the name of the nor the 15 | names of its contributors may be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include "env.h" 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | static Env* env_instance = Q_NULLPTR; 38 | 39 | Env* Env::instance() 40 | { 41 | if (!env_instance) { 42 | env_instance = new Env(); 43 | } 44 | 45 | return env_instance; 46 | } 47 | 48 | Env::Env() 49 | : QObject(QCoreApplication::instance()) 50 | { 51 | const QProcessEnvironment& env = QProcessEnvironment::systemEnvironment(); 52 | foreach (const QString& key, env.keys()) { 53 | m_map[key] = env.value(key); 54 | } 55 | } 56 | 57 | // public: 58 | 59 | QVariantMap Env::asVariantMap() const 60 | { 61 | return m_map; 62 | } 63 | -------------------------------------------------------------------------------- /src/env.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhantomJS project from Ofi Labs. 3 | 4 | Copyright (C) 2012 execjosh, http://execjosh.blogspot.com 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | * Neither the name of the nor the 15 | names of its contributors may be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef ENV_H 31 | #define ENV_H 32 | 33 | #include 34 | #include 35 | 36 | class Env : public QObject { 37 | Q_OBJECT 38 | 39 | public: 40 | static Env* instance(); 41 | 42 | QVariantMap asVariantMap() const; 43 | 44 | private: 45 | Env(); 46 | 47 | QVariantMap m_map; 48 | }; 49 | 50 | #endif // ENV_H 51 | -------------------------------------------------------------------------------- /src/linenoise/README.md: -------------------------------------------------------------------------------- 1 | This project contains the **Linenoise project**, initially released 2 | by [Salvatore Sanfilippo](https://github.com/antirez). Here we import a fork 3 | by [Tad Marshall](https://github.com/tadmarshall) that lives at 4 | [github.com/tadmarshall/linenoise](https://github.com/tadmarshall/linenoise). 5 | 6 | The version of Linenoise included in PhantomJS refers to the commit: 7 | ----- 8 | commit 7946e2c2d08df11dca2b99c5db40360c3d3e9a80 9 | Author: Alan T. DeKok 10 | Date: Wed Oct 26 15:56:52 2011 +0200 11 | 12 | Added character callbacks again 13 | ----- 14 | 15 | Some files not needed for PhantomJS are removed. 16 | 17 | Linenoise is licensed under the BSD-license. 18 | Kudos to all the developers that contribute to this nice little pearl. 19 | -------------------------------------------------------------------------------- /src/linenoise/src/example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "linenoise.h" 4 | 5 | #ifndef NO_COMPLETION 6 | void completion(const char *buf, linenoiseCompletions *lc) { 7 | if (buf[0] == 'h') { 8 | linenoiseAddCompletion(lc,"hello"); 9 | linenoiseAddCompletion(lc,"hello there"); 10 | } 11 | } 12 | #endif 13 | 14 | static int in_string = 0; 15 | static size_t string_start = 0; 16 | 17 | int foundspace(const char *buf, size_t len, char c) { 18 | if (in_string) return 0; 19 | 20 | if (len == 0) return 1; 21 | 22 | if (buf[len -1] == c) return 1; 23 | 24 | printf("\r\nSPACE!\r\n"); 25 | return 0; 26 | } 27 | 28 | int escapedquote(const char *start) 29 | { 30 | while (*start) { 31 | if (*start == '\\') { 32 | if (!start[1]) return 1; 33 | start += 2; 34 | } 35 | start++; 36 | } 37 | return 0; 38 | } 39 | 40 | 41 | int foundquote(const char *buf, size_t len, char c) { 42 | if (!in_string) { 43 | in_string = 1; 44 | string_start = len; 45 | return 0; 46 | } 47 | 48 | if (buf[string_start] != c) return 0; 49 | 50 | if (escapedquote(buf + string_start)) return 0; 51 | 52 | in_string = 0; 53 | printf("\r\nSTRING %s%c\r\n", buf + string_start, buf[string_start]); 54 | string_start = 0; 55 | 56 | return 0; 57 | } 58 | 59 | int foundhelp(const char *buf, size_t len, char c) { 60 | if (in_string) return 0; 61 | 62 | len = len; /* -Wunused */ 63 | c = c; /* -Wunused */ 64 | 65 | printf("?\r\nHELP: %s\r\n", buf); 66 | return 1; 67 | } 68 | 69 | int main(void) { 70 | char *line; 71 | 72 | #ifndef NO_COMPLETION 73 | linenoiseSetCompletionCallback(completion); 74 | #endif 75 | linenoiseHistoryLoad("history.txt"); /* Load the history at startup */ 76 | linenoiseSetCharacterCallback(foundspace, ' '); 77 | linenoiseSetCharacterCallback(foundquote, '"'); 78 | linenoiseSetCharacterCallback(foundquote, '\''); 79 | linenoiseSetCharacterCallback(foundhelp, '?'); 80 | 81 | while((line = linenoise("hello> ")) != NULL) { 82 | if (line[0] != '\0') { 83 | printf("echo: '%s'\n", line); 84 | linenoiseHistoryAdd(line); 85 | linenoiseHistorySave("history.txt"); /* Save every new entry */ 86 | } 87 | free(line); 88 | } 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /src/linenoise/src/linenoise.h: -------------------------------------------------------------------------------- 1 | /* linenoise.h -- guerrilla line editing library against the idea that a 2 | * line editing lib needs to be 20,000 lines of C code. 3 | * 4 | * See linenoise.c for more information. 5 | * 6 | * ------------------------------------------------------------------------ 7 | * 8 | * Copyright (c) 2010, Salvatore Sanfilippo 9 | * Copyright (c) 2010, Pieter Noordhuis 10 | * 11 | * All rights reserved. 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are 15 | * met: 16 | * 17 | * * Redistributions of source code must retain the above copyright 18 | * notice, this list of conditions and the following disclaimer. 19 | * 20 | * * Redistributions in binary form must reproduce the above copyright 21 | * notice, this list of conditions and the following disclaimer in the 22 | * documentation and/or other materials provided with the distribution. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #ifndef __LINENOISE_H 38 | #define __LINENOISE_H 39 | 40 | #ifndef NO_COMPLETION 41 | typedef struct linenoiseCompletions { 42 | size_t len; 43 | char **cvec; 44 | } linenoiseCompletions; 45 | 46 | typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); 47 | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); 48 | void linenoiseAddCompletion(linenoiseCompletions *, const char *); 49 | #endif 50 | 51 | typedef int(linenoiseCharacterCallback)(const char *, size_t, char); 52 | void linenoiseSetCharacterCallback(linenoiseCharacterCallback *, char); 53 | 54 | char *linenoise(const char *prompt); 55 | int linenoiseHistoryAdd(const char *line); 56 | int linenoiseHistorySetMaxLen(int len); 57 | int linenoiseHistorySave(const char *filename); 58 | int linenoiseHistoryLoad(const char *filename); 59 | void linenoiseHistoryFree(void); 60 | char **linenoiseHistory(int *len); 61 | 62 | #endif /* __LINENOISE_H */ 63 | -------------------------------------------------------------------------------- /src/linenoise/src/utf8.c: -------------------------------------------------------------------------------- 1 | /** 2 | * UTF-8 utility functions 3 | * 4 | * (c) 2010 Steve Bennett 5 | * 6 | * See LICENCE for licence details. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "utf8.h" 14 | 15 | #ifdef USE_UTF8 16 | int utf8_fromunicode(char *p, unsigned short uc) 17 | { 18 | if (uc <= 0x7f) { 19 | *p = uc; 20 | return 1; 21 | } 22 | else if (uc <= 0x7ff) { 23 | *p++ = 0xc0 | ((uc & 0x7c0) >> 6); 24 | *p = 0x80 | (uc & 0x3f); 25 | return 2; 26 | } 27 | else { 28 | *p++ = 0xe0 | ((uc & 0xf000) >> 12); 29 | *p++ = 0x80 | ((uc & 0xfc0) >> 6); 30 | *p = 0x80 | (uc & 0x3f); 31 | return 3; 32 | } 33 | } 34 | 35 | int utf8_charlen(int c) 36 | { 37 | if ((c & 0x80) == 0) { 38 | return 1; 39 | } 40 | if ((c & 0xe0) == 0xc0) { 41 | return 2; 42 | } 43 | if ((c & 0xf0) == 0xe0) { 44 | return 3; 45 | } 46 | if ((c & 0xf8) == 0xf0) { 47 | return 4; 48 | } 49 | /* Invalid sequence */ 50 | return -1; 51 | } 52 | 53 | int utf8_strlen(const char *str, int bytelen) 54 | { 55 | int charlen = 0; 56 | if (bytelen < 0) { 57 | bytelen = strlen(str); 58 | } 59 | while (bytelen) { 60 | int c; 61 | int l = utf8_tounicode(str, &c); 62 | charlen++; 63 | str += l; 64 | bytelen -= l; 65 | } 66 | return charlen; 67 | } 68 | 69 | int utf8_index(const char *str, int index) 70 | { 71 | const char *s = str; 72 | while (index--) { 73 | int c; 74 | s += utf8_tounicode(s, &c); 75 | } 76 | return s - str; 77 | } 78 | 79 | int utf8_charequal(const char *s1, const char *s2) 80 | { 81 | int c1, c2; 82 | 83 | utf8_tounicode(s1, &c1); 84 | utf8_tounicode(s2, &c2); 85 | 86 | return c1 == c2; 87 | } 88 | 89 | int utf8_tounicode(const char *str, int *uc) 90 | { 91 | unsigned const char *s = (unsigned const char *)str; 92 | 93 | if (s[0] < 0xc0) { 94 | *uc = s[0]; 95 | return 1; 96 | } 97 | if (s[0] < 0xe0) { 98 | if ((s[1] & 0xc0) == 0x80) { 99 | *uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80); 100 | return 2; 101 | } 102 | } 103 | else if (s[0] < 0xf0) { 104 | if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80)) { 105 | *uc = ((s[0] & ~0xe0) << 12) | ((s[1] & ~0x80) << 6) | (s[2] & ~0x80); 106 | return 3; 107 | } 108 | } 109 | 110 | /* Invalid sequence, so just return the byte */ 111 | *uc = *s; 112 | return 1; 113 | } 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /src/linenoise/src/utf8.h: -------------------------------------------------------------------------------- 1 | #ifndef UTF8_UTIL_H 2 | #define UTF8_UTIL_H 3 | /** 4 | * UTF-8 utility functions 5 | * 6 | * (c) 2010 Steve Bennett 7 | * 8 | * See LICENCE for licence details. 9 | */ 10 | 11 | #ifndef USE_UTF8 12 | #include 13 | 14 | /* No utf-8 support. 1 byte = 1 char */ 15 | #define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B)) 16 | #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1) 17 | #define utf8_index(C, I) (I) 18 | #define utf8_charlen(C) 1 19 | 20 | #else 21 | /** 22 | * Converts the given unicode codepoint (0 - 0xffff) to utf-8 23 | * and stores the result at 'p'. 24 | * 25 | * Returns the number of utf-8 characters (1-3). 26 | */ 27 | int utf8_fromunicode(char *p, unsigned short uc); 28 | 29 | /** 30 | * Returns the length of the utf-8 sequence starting with 'c'. 31 | * 32 | * Returns 1-4, or -1 if this is not a valid start byte. 33 | * 34 | * Note that charlen=4 is not supported by the rest of the API. 35 | */ 36 | int utf8_charlen(int c); 37 | 38 | /** 39 | * Returns the number of characters in the utf-8 40 | * string of the given byte length. 41 | * 42 | * Any bytes which are not part of an valid utf-8 43 | * sequence are treated as individual characters. 44 | * 45 | * The string *must* be null terminated. 46 | * 47 | * Does not support unicode code points > \uffff 48 | */ 49 | int utf8_strlen(const char *str, int bytelen); 50 | 51 | /** 52 | * Returns the byte index of the given character in the utf-8 string. 53 | * 54 | * The string *must* be null terminated. 55 | * 56 | * This will return the byte length of a utf-8 string 57 | * if given the char length. 58 | */ 59 | int utf8_index(const char *str, int charindex); 60 | 61 | /** 62 | * Returns the unicode codepoint corresponding to the 63 | * utf-8 sequence 'str'. 64 | * 65 | * Stores the result in *uc and returns the number of bytes 66 | * consumed. 67 | * 68 | * If 'str' is null terminated, then an invalid utf-8 sequence 69 | * at the end of the string will be returned as individual bytes. 70 | * 71 | * If it is not null terminated, the length *must* be checked first. 72 | * 73 | * Does not support unicode code points > \uffff 74 | */ 75 | int utf8_tounicode(const char *str, int *uc); 76 | 77 | #endif 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/modules/cookiejar.js: -------------------------------------------------------------------------------- 1 | /*jslint sloppy: true, nomen: true */ 2 | /*global exports:true */ 3 | 4 | /* 5 | This file is part of the PhantomJS project from Ofi Labs. 6 | 7 | Copyright (C) 2013 Joseph Rollinson, jtrollinson@gmail.com 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | 12 | * Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | * Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | * Neither the name of the nor the 18 | names of its contributors may be used to endorse or promote products 19 | derived from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 25 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* Only there for backwards compatibility. */ 34 | function decorateCookieJar(jar) { 35 | return jar; 36 | } 37 | 38 | /* Creates and decorates a new cookie jar. 39 | * path is the file path where Phantomjs will store the cookie jar persistently. 40 | * path is not mandatory. 41 | */ 42 | exports.create = function (path) { 43 | if (arguments.length < 1) { 44 | path = ""; 45 | } 46 | return decorateCookieJar(phantom.createCookieJar(path)); 47 | }; 48 | 49 | /* Exports the decorateCookieJar function */ 50 | exports.decorate = decorateCookieJar; 51 | -------------------------------------------------------------------------------- /src/modules/system.js: -------------------------------------------------------------------------------- 1 | /* 2 | * CommonJS System/1.0 3 | * Spec: http://wiki.commonjs.org/wiki/System/1.0 4 | */ 5 | 6 | exports.platform = 'phantomjs'; 7 | 8 | Object.defineProperty(exports, 'stdout', { 9 | enumerable: true, 10 | writeable: false, 11 | get: function() { 12 | return exports.standardout; 13 | } 14 | }); 15 | 16 | Object.defineProperty(exports, 'stdin', { 17 | enumerable: true, 18 | writeable: false, 19 | get: function() { 20 | return exports.standardin; 21 | } 22 | }); 23 | 24 | Object.defineProperty(exports, 'stderr', { 25 | enumerable: true, 26 | writeable: false, 27 | get: function() { 28 | return exports.standarderr; 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /src/mongoose/ReadMe.txt: -------------------------------------------------------------------------------- 1 | This project contains version 3.1 of the Mongoose web server project, as 2 | found at http://code.google.com/p/mongoose. 3 | 4 | It contains the code for version 3.1 as of 26-May-2011 (revision 0ca751520abf). 5 | It contains an additional change in pthread_cond_broadcast() [~line 865] to 6 | improve stability when running a debug build. 7 | -------------------------------------------------------------------------------- /src/phantomjs-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/src/phantomjs-icon.png -------------------------------------------------------------------------------- /src/phantomjs.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | phantomjs-icon.png 4 | bootstrap.js 5 | configurator.js 6 | modules/webpage.js 7 | modules/webserver.js 8 | modules/fs.js 9 | modules/system.js 10 | modules/child_process.js 11 | modules/cookiejar.js 12 | repl.js 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/phantomjs_win.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/src/phantomjs_win.ico -------------------------------------------------------------------------------- /src/phantomjs_win.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "phantomjs_win.ico" 2 | 3 | #include 4 | #include "consts.h" 5 | 6 | VS_VERSION_INFO VERSIONINFO 7 | FILEVERSION PHANTOMJS_VERSION_MAJOR,PHANTOMJS_VERSION_MINOR,PHANTOMJS_VERSION_PATCH 8 | PRODUCTVERSION PHANTOMJS_VERSION_MAJOR,PHANTOMJS_VERSION_MINOR,PHANTOMJS_VERSION_PATCH 9 | BEGIN 10 | BLOCK "StringFileInfo" 11 | BEGIN 12 | BLOCK "040904E4" 13 | BEGIN 14 | VALUE "FileDescription", "PhantomJS is a headless WebKit with JavaScript API" 15 | VALUE "FileVersion", PHANTOMJS_VERSION_STRING 16 | VALUE "LegalCopyright", "Copyright (C) Ariya Hidayat 2012" 17 | VALUE "OriginalFilename", "phantomjs.exe" 18 | VALUE "ProductName", "PhantomJS" 19 | VALUE "ProductVersion", PHANTOMJS_VERSION_STRING 20 | VALUE "CompanyName", "PhantomJS" 21 | END 22 | END 23 | 24 | BLOCK "VarFileInfo" 25 | BEGIN 26 | VALUE "Translation", 0x409, 1252 27 | END 28 | END 29 | -------------------------------------------------------------------------------- /src/terminal.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhantomJS project from Ofi Labs. 3 | 4 | Copyright (C) 2011 Ariya Hidayat 5 | Copyright (C) 2011 execjosh, http://execjosh.blogspot.com 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | * Neither the name of the nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef TERMINAL_H 32 | #define TERMINAL_H 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include "encoding.h" 39 | 40 | class Terminal : public QObject { 41 | Q_OBJECT 42 | 43 | public: 44 | static Terminal* instance(); 45 | 46 | QString getEncoding() const; 47 | bool setEncoding(const QString& encoding); 48 | 49 | void cout(const QString& string, const bool newline = true) const; 50 | void cerr(const QString& string, const bool newline = true) const; 51 | 52 | signals: 53 | void encodingChanged(const QString& encoding); 54 | 55 | private: 56 | void output(std::ostream& out, const QString& string, const bool newline) const; 57 | 58 | private: 59 | Terminal(); 60 | Encoding m_encoding; 61 | }; 62 | 63 | #endif // TERMINAL_H 64 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhantomJS project from Ofi Labs. 3 | 4 | Copyright (C) 2011 Ariya Hidayat 5 | Copyright (C) 2011 Ivan De Marino 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | * Neither the name of the nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef UTILS_H 32 | #define UTILS_H 33 | 34 | #include "encoding.h" 35 | #include 36 | 37 | class QWebFrame; 38 | 39 | /** 40 | * Aggregate common utility functions. 41 | */ 42 | 43 | namespace Utils { 44 | 45 | void messageHandler(QtMsgType type, 46 | const QMessageLogContext& context, 47 | const QString& msg); 48 | extern bool printDebugMessages; 49 | 50 | bool injectJsInFrame(const QString& jsFilePath, 51 | const Encoding& jsFileEnc, 52 | const QString& libraryPath, 53 | QWebFrame* targetFrame, 54 | const bool startingScript = false); 55 | 56 | bool loadJSForDebug(const QString& jsFilePath, 57 | const Encoding& jsFileEnc, 58 | const QString& libraryPath, 59 | QWebFrame* targetFrame, 60 | const bool autorun = false); 61 | 62 | QString readResourceFileUtf8(const QString& resourceFilePath); 63 | }; 64 | 65 | #endif // UTILS_H 66 | -------------------------------------------------------------------------------- /test/basics/exit0.js: -------------------------------------------------------------------------------- 1 | //! no-harness 2 | //! expect-exit: 0 3 | //! expect-stdout: "we are alive" 4 | //! expect-stdout-fails 5 | 6 | var sys = require('system'); 7 | sys.stdout.write("we are alive\n"); 8 | phantom.exit(); 9 | sys.stdout.write("ERROR control passed beyond phantom.exit"); 10 | -------------------------------------------------------------------------------- /test/basics/exit23.js: -------------------------------------------------------------------------------- 1 | //! no-harness 2 | //! expect-exit: 23 3 | //! expect-stdout: "we are alive" 4 | //! expect-stdout-fails 5 | 6 | var sys = require('system'); 7 | sys.stdout.write("we are alive\n"); 8 | phantom.exit(23); 9 | sys.stdout.write("ERROR control passed beyond phantom.exit"); 10 | -------------------------------------------------------------------------------- /test/basics/module.js: -------------------------------------------------------------------------------- 1 | // Test the properties of the 'module' object. 2 | // Assumes the 'dummy_exposed' module is to be found in a directory 3 | // named 'node_modules'. 4 | 5 | // Module load might fail, so do it in a setup function. 6 | var module; 7 | setup(function () { 8 | module = require("dummy_exposed"); 9 | }); 10 | 11 | test(function() { 12 | assert_regexp_match(module.filename, /\/node_modules\/dummy_exposed\.js$/); 13 | }, "module.filename is the absolute pathname of the module .js file"); 14 | 15 | test(function() { 16 | assert_regexp_match(module.dirname, /\/node_modules$/); 17 | }, "module.dirname is the absolute pathname of the directory containing "+ 18 | "the module"); 19 | 20 | test(function() { 21 | assert_equals(module.id, module.filename); 22 | }, "module.id equals module.filename"); 23 | 24 | test(function() { 25 | var dummy_file = module.require('./dummy_file'); 26 | assert_equals(dummy_file, 'spec/node_modules/dummy_file'); 27 | }, "module.require is callable and resolves relative to the module"); 28 | -------------------------------------------------------------------------------- /test/basics/phantom-object.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | assert_type_of(phantom, 'object'); 3 | }, "phantom object"); 4 | 5 | test(function () { 6 | assert_own_property(phantom, 'libraryPath'); 7 | assert_type_of(phantom.libraryPath, 'string'); 8 | assert_greater_than(phantom.libraryPath.length, 0); 9 | }, "phantom.libraryPath"); 10 | 11 | test(function () { 12 | assert_own_property(phantom, 'outputEncoding'); 13 | assert_type_of(phantom.outputEncoding, 'string'); 14 | assert_equals(phantom.outputEncoding.toLowerCase(), 'utf-8'); // default 15 | }, "phantom.outputEncoding"); 16 | 17 | test(function () { 18 | assert_own_property(phantom, 'injectJs'); 19 | assert_type_of(phantom.injectJs, 'function'); 20 | }, "phantom.injectJs"); 21 | 22 | test(function () { 23 | assert_own_property(phantom, 'exit'); 24 | assert_type_of(phantom.exit, 'function'); 25 | }, "phantom.exit"); 26 | 27 | test(function () { 28 | assert_own_property(phantom, 'cookiesEnabled'); 29 | assert_type_of(phantom.cookiesEnabled, 'boolean'); 30 | assert_is_true(phantom.cookiesEnabled); 31 | }, "phantom.cookiesEnabled"); 32 | 33 | test(function () { 34 | assert_own_property(phantom, 'version'); 35 | assert_type_of(phantom.version, 'object'); 36 | assert_type_of(phantom.version.major, 'number'); 37 | assert_type_of(phantom.version.minor, 'number'); 38 | assert_type_of(phantom.version.patch, 'number'); 39 | }, "phantom.version"); 40 | -------------------------------------------------------------------------------- /test/basics/require.js: -------------------------------------------------------------------------------- 1 | //! expect-exit: 1 2 | //! expect-stdout: "1..0" 3 | //! expect-stdout: "# ERROR: Global timeout expired" 4 | 5 | /* The require tests need to run inside a module to work correctly; that 6 | module is require/require_spec.js. (That directory also contains a 7 | bunch of other files used by this test.) The module exports an array 8 | of test functions in the form expected by generate_tests(). */ 9 | 10 | var rtests = require("require/require_spec.js").tests; 11 | 12 | for (var i = 0; i < rtests.length; i++) { 13 | // skip: FIXME 14 | // test.apply(null, rtests[i]); 15 | } 16 | -------------------------------------------------------------------------------- /test/basics/require/a.js: -------------------------------------------------------------------------------- 1 | var b = require('./b'); 2 | exports.b = b; 3 | -------------------------------------------------------------------------------- /test/basics/require/b.js: -------------------------------------------------------------------------------- 1 | var a = require('./a'); 2 | exports.a = a; 3 | -------------------------------------------------------------------------------- /test/basics/require/dir/dummy.js: -------------------------------------------------------------------------------- 1 | module.exports = 'dir/dummy'; 2 | -------------------------------------------------------------------------------- /test/basics/require/dir/subdir/dummy.js: -------------------------------------------------------------------------------- 1 | module.exports = 'subdir/dummy'; 2 | -------------------------------------------------------------------------------- /test/basics/require/dir/subdir/loader.js: -------------------------------------------------------------------------------- 1 | exports.dummyFile2 = require('dummy_file2'); 2 | -------------------------------------------------------------------------------- /test/basics/require/dir/subdir2/loader.js: -------------------------------------------------------------------------------- 1 | module.exports = 'require/subdir2/loader' 2 | -------------------------------------------------------------------------------- /test/basics/require/dummy.js: -------------------------------------------------------------------------------- 1 | module.exports = 'require/dummy'; 2 | -------------------------------------------------------------------------------- /test/basics/require/empty.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/test/basics/require/empty.js -------------------------------------------------------------------------------- /test/basics/require/json_dummy.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "hello" 3 | } 4 | -------------------------------------------------------------------------------- /test/basics/require/node_modules/dummy_file.js: -------------------------------------------------------------------------------- 1 | module.exports = 'require/node_modules/dummy_file'; 2 | -------------------------------------------------------------------------------- /test/basics/require/node_modules/dummy_module/libdir/dummy_module.js: -------------------------------------------------------------------------------- 1 | module.exports = 'require/node_modules/dummy_module'; 2 | -------------------------------------------------------------------------------- /test/basics/require/node_modules/dummy_module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dummy", 3 | "main": "./libdir/dummy_module.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/basics/require/node_modules/dummy_module2/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 'require/node_modules/dummy_module2'; 2 | -------------------------------------------------------------------------------- /test/basics/require/not_found.js: -------------------------------------------------------------------------------- 1 | exports.requireNonExistent = function() { 2 | require('./non_existent'); 3 | }; 4 | -------------------------------------------------------------------------------- /test/basics/require/stubber.js: -------------------------------------------------------------------------------- 1 | require.stub('stubbed', 'stubbed module'); 2 | exports.stubbed = require('stubbed'); 3 | try { 4 | exports.child = require('./stubber_child'); 5 | } catch (e) {} 6 | -------------------------------------------------------------------------------- /test/basics/require/stubber_child.js: -------------------------------------------------------------------------------- 1 | exports.stubbed = require('stubbed'); 2 | -------------------------------------------------------------------------------- /test/basics/require/thrower.js: -------------------------------------------------------------------------------- 1 | exports.fn = function thrower() { 2 | throw new Error('fn'); 3 | }; 4 | -------------------------------------------------------------------------------- /test/basics/stacktrace.js: -------------------------------------------------------------------------------- 1 | 2 | // A SyntaxError leaks to phantom.onError, despite the try-catch. 3 | setup({ allow_uncaught_exception: true }); 4 | 5 | test(function () { 6 | var helperFile = "../fixtures/parse-error-helper.js"; 7 | try { 8 | phantom.injectJs(helperFile); 9 | } catch (e) { 10 | assert_equals(e.stack[0].file, helperFile); 11 | assert_equals(e.stack[0].line, 2); 12 | } 13 | }, "stack trace from syntax error in injected file"); 14 | -------------------------------------------------------------------------------- /test/basics/test-server.js: -------------------------------------------------------------------------------- 1 | /* Test the test server itself. */ 2 | 3 | var webpage = require('webpage'); 4 | 5 | function test_one_page(url) { 6 | var page = webpage.create(); 7 | page.onResourceReceived = this.step_func(function (response) { 8 | assert_equals(response.status, 200); 9 | }); 10 | page.onResourceError = this.unreached_func(); 11 | page.onResourceTimeout = this.unreached_func(); 12 | page.onLoadFinished = this.step_func_done(function (status) { 13 | assert_equals(status, 'success'); 14 | }); 15 | page.open(url); 16 | } 17 | 18 | function do_test(path) { 19 | var http_url = TEST_HTTP_BASE + path; 20 | var https_url = TEST_HTTPS_BASE + path; 21 | var http_test = async_test(http_url); 22 | var https_test = async_test(https_url); 23 | http_test.step(test_one_page, null, http_url); 24 | https_test.step(test_one_page, null, https_url); 25 | } 26 | 27 | [ 28 | 'hello.html', 29 | 'status?200', 30 | 'echo' 31 | ] 32 | .forEach(do_test); 33 | -------------------------------------------------------------------------------- /test/basics/timeout.js: -------------------------------------------------------------------------------- 1 | //! no-harness 2 | //! expect-exit: -15 3 | //! expect-stderr: TIMEOUT: Process terminated after 0.25 seconds. 4 | //! timeout: 0.25 5 | 6 | // no code, so phantom will just sleep forever 7 | -------------------------------------------------------------------------------- /test/basics/url-utils.js: -------------------------------------------------------------------------------- 1 | // These are cursory tests; we assume the underlying Qt 2 | // features are properly tested elsewhere. 3 | 4 | test(function () { 5 | assert_equals( 6 | phantom.resolveRelativeUrl( 7 | "../scripts/foo.js", 8 | "http://example.com/topic/page.html"), 9 | "http://example.com/scripts/foo.js"); 10 | 11 | assert_equals( 12 | phantom.fullyDecodeUrl( 13 | "https://ja.wikipedia.org/wiki/%E8%87%A8%E6%B5%B7%E5%AD%A6%E6%A0%A1"), 14 | "https://ja.wikipedia.org/wiki/臨海学校"); 15 | 16 | }, "resolveRelativeUrl and fullyDecodeUrl"); 17 | -------------------------------------------------------------------------------- /test/basics/version.js: -------------------------------------------------------------------------------- 1 | // This is separate from basics/phantom-object.js because it has to be 2 | // updated with every release. 3 | test(function () { 4 | assert_equals(phantom.version.major, 3); 5 | assert_equals(phantom.version.minor, 0); 6 | assert_equals(phantom.version.patch, 0); 7 | }, "PhantomJS version number is accurate"); 8 | -------------------------------------------------------------------------------- /test/lib/certs/https-snakeoil.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC+zCCAeOgAwIBAgIJAJ7HwZBrgnLwMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV 3 | BAMMCWxvY2FsaG9zdDAeFw0xNTA4MTEyMjU4MTZaFw0yNTA4MTAyMjU4MTZaMBQx 4 | EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 5 | ggEBANFha8c5JKjYrHc7BTqmuFSAxYsSKbUUa0k+0PFpjhj7Io/NOeHhxfdLJX/B 6 | LVQXEDhvOlSTDBgC3RQkxCZJmMzKZjMDlj0cxY0esZtcqt0sRpwRvT+EBE9SlFu4 7 | TWM2BQ6k5E4OIX/9aUk9HQ99pSjqmhu/7n76n/5DfqxGwkfVZengI1KwfezaB5+Q 8 | wAvoS7tadROqTyynV1kd+OF9BJZwO1eR9lAiGc139J/BHegVcqdrI043oR+1vyTw 9 | BFpodw4HYdJHNgo7DKAtmXoDAws5myqx2GcnVng1wyzu6LdM65nMV4/p5Y/Y6Ziy 10 | RqeV1gVbtpxTcrLmWFnI8BRwFBUCAwEAAaNQME4wHQYDVR0OBBYEFPP1YOkZpJmE 11 | x/W48Kwv2N1QC1oDMB8GA1UdIwQYMBaAFPP1YOkZpJmEx/W48Kwv2N1QC1oDMAwG 12 | A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAA1NxsrmKxGecAS6TEHNBqFZ 13 | 9NhV23kXY5sdv8zl7HUmzR+vIBumd9lkSZdOwAy5/hmj6ACReSJ9f2xpyi0fOtx5 14 | WZ8Vcrg9Qjuy17qmGi66yL860yr0h6hltzCWCi7e26Eybawm3/9PmbNV3Hcwgxug 15 | D+gv4LZLlyj4JI4lg/8RVXaNXqGBZ39YhRH0LFVjbYiFWUGqzfAT9YBoC67Ov8Yv 16 | Bl1PoV3sJcagx67X6y8ru+gecc/OOXKJHxSidhjRqhKB6WOWIPfugsMOl1g2FMPv 17 | tuPFsIQNSaln7V+ECeDOipJOSp9KAyM5fNcVjldd/e4V+qwcyoOijFywNfSK10M= 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /test/lib/certs/https-snakeoil.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDRYWvHOSSo2Kx3 3 | OwU6prhUgMWLEim1FGtJPtDxaY4Y+yKPzTnh4cX3SyV/wS1UFxA4bzpUkwwYAt0U 4 | JMQmSZjMymYzA5Y9HMWNHrGbXKrdLEacEb0/hARPUpRbuE1jNgUOpORODiF//WlJ 5 | PR0PfaUo6pobv+5++p/+Q36sRsJH1WXp4CNSsH3s2gefkMAL6Eu7WnUTqk8sp1dZ 6 | HfjhfQSWcDtXkfZQIhnNd/SfwR3oFXKnayNON6Eftb8k8ARaaHcOB2HSRzYKOwyg 7 | LZl6AwMLOZsqsdhnJ1Z4NcMs7ui3TOuZzFeP6eWP2OmYskanldYFW7acU3Ky5lhZ 8 | yPAUcBQVAgMBAAECggEAOwI/w8fhAwz9niSuFpeB/57DDayywGveyKfBbygWegfc 9 | 97YZCAX/KvCswtKImdheI+mFAOzoTaQQ9mpeNYQsYhrwrpPmNZb0Pg9WcritFuQx 10 | ii6drVbheBGH6kmI1dsVlcj25uCopE+g6pkkpYb9kwh7IjL3XiX4DUqsWpUej+ub 11 | 2iL/luW7nYHHIRqzOFgP3v/f29sFHNvYcgihphBMHtgb4VpeYQ/f7AC7k1bFYfA/ 12 | TmvfUcXdiPwJf0XICZOaLrT/6pigk0bRiLNn8npISu7Wlf4jF60bNAe4+krBVU4O 13 | p8UjW99LiGKLDh8GpoudnzlnnngZ3SA5+bO7kwTjCQKBgQDvJwUShOWm2+5wJsr4 14 | hWieTVDaZEDb+1WTe7DwtqRWNBWXchh8is9buWeXIe6+1WldBYYiQjgdggQCw8xG 15 | IFFg1j1E6kPqk/kzrHYSsJ+/u8uaxypvvrVBhUqt5FduOxFojW2REX9W5n8HTdT4 16 | 32BGR4mGpuXzR+BsVK00QRgM+wKBgQDgIXtu6rbfx+mdXTFi6apWJoyu5bRWcrL2 17 | mGoR+IjCk6NefcvBE33q54H/dk3+0Sxp6+uFo7lyKv4EL3lozQO2oga6sp2LOIEK 18 | DUo+KQVOmntCNrjuN/PbjSu2s1j5QDnLNR9VvXGiYBWdpZ7k3YzoKJ1I4ZyB3kGs 19 | H/lCXv52LwKBgER1HvaWJEcHXdGsyR0q0y+9Yg+h8w8FexGkrpm5LoGely+q8Wd1 20 | NLZE9GpGxFjMLkT6d9MGsZmAxjUkZy0Lwz+9E/zOMnLLuOIZ1BK1jIUN9NJxgKxM 21 | IwaGaUItwvlC31DWay7Dm3f8sxAcL4KuLpjvkWaCEAD76joYYxw6JfBRAoGADMe7 22 | +xolLWN/3bpHq6U5UkpGcV6lxtwpekg8nCO44Kd8hFHWAX90CaYD0qZTUjlpN+z8 23 | 9BTe6TSsYV63pJM0KADbM2Al/Z9ONF2Hoz3BkLbcWm02ZFcKb7WADZ3yb9wKr5yq 24 | 2b/AsAqckO21vsUnWMGgHlzHCNy8j+0O0IsMJX8CgYAORhyGaU7x5t4kEvqBNIan 25 | mOzuB0b5nYV9mHxmyFhOsa8LeM25SA4n1rFpTb8h6vmZF1y9+4Zy4uNfCR2wXg0v 26 | I51qtZ8npbIksYvNqvHaTPg8ZBcFK5mHr3TDxXJCcc0ylzM98ze08D+qKr0joX4w 27 | KlqN6KjGmYfb+RHehLk9sw== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /test/lib/fixtures/cat.py: -------------------------------------------------------------------------------- 1 | # Platform-agnostic replacement for 'cat' with no arguments. 2 | # Avoids 'print' to achieve Python 2/3 agnosticism as well. 3 | import sys 4 | sys.stdout.write(sys.stdin.read()) 5 | -------------------------------------------------------------------------------- /test/lib/fixtures/dummy.js: -------------------------------------------------------------------------------- 1 | module.exports = 'spec/dummy'; 2 | -------------------------------------------------------------------------------- /test/lib/fixtures/echo.py: -------------------------------------------------------------------------------- 1 | # Platform-agnostic replacement for 'echo -n'. 2 | # Avoids 'print' to achieve Python 2/3 agnosticism as well. 3 | import sys 4 | sys.stdout.write(" ".join(sys.argv[1:])) 5 | -------------------------------------------------------------------------------- /test/lib/fixtures/error-helper.js: -------------------------------------------------------------------------------- 1 | ErrorHelper = { 2 | foo: function() { 3 | this.bar() 4 | }, 5 | 6 | bar: function bar() { 7 | referenceError 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /test/lib/fixtures/parse-error-helper.js: -------------------------------------------------------------------------------- 1 | var ok; 2 | bar("run away" -------------------------------------------------------------------------------- /test/lib/node_modules/dummy_exposed.js: -------------------------------------------------------------------------------- 1 | module.exports = module; 2 | -------------------------------------------------------------------------------- /test/lib/node_modules/dummy_file.js: -------------------------------------------------------------------------------- 1 | module.exports = 'spec/node_modules/dummy_file'; 2 | -------------------------------------------------------------------------------- /test/lib/node_modules/dummy_file2.js: -------------------------------------------------------------------------------- 1 | module.exports = 'spec/node_modules/dummy_file2'; 2 | -------------------------------------------------------------------------------- /test/lib/www/__init__.py: -------------------------------------------------------------------------------- 1 | # This file makes test/www/ into a "package" so that 2 | # importing Python response hooks works correctly. 3 | -------------------------------------------------------------------------------- /test/lib/www/delay.py: -------------------------------------------------------------------------------- 1 | import cStringIO as StringIO 2 | import urlparse 3 | import time 4 | 5 | def handle_request(req): 6 | url = urlparse.urlparse(req.path) 7 | delay = float(int(url.query)) 8 | time.sleep(delay / 1000) # argument is in milliseconds 9 | 10 | body = "OK ({}ms delayed)\n".format(delay) 11 | req.send_response(200) 12 | req.send_header('Content-Type', 'text/plain') 13 | req.send_header('Content-Length', str(len(body))) 14 | req.end_headers() 15 | return StringIO.StringIO(body) 16 | -------------------------------------------------------------------------------- /test/lib/www/echo.py: -------------------------------------------------------------------------------- 1 | import json 2 | import urlparse 3 | import cStringIO as StringIO 4 | 5 | def handle_request(req): 6 | url = urlparse.urlparse(req.path) 7 | headers = {} 8 | for name, value in req.headers.items(): 9 | headers[name] = value.rstrip() 10 | 11 | d = dict( 12 | command = req.command, 13 | version = req.protocol_version, 14 | origin = req.client_address, 15 | url = req.path, 16 | path = url.path, 17 | params = url.params, 18 | query = url.query, 19 | fragment = url.fragment, 20 | headers = headers, 21 | postdata = req.postdata 22 | ) 23 | body = json.dumps(d, indent=2) + '\n' 24 | 25 | req.send_response(200) 26 | req.send_header('Content-Type', 'application/json') 27 | req.send_header('Content-Length', str(len(body))) 28 | req.end_headers() 29 | return StringIO.StringIO(body) 30 | -------------------------------------------------------------------------------- /test/lib/www/frameset/frame1-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | frame1-1 4 | 5 | 6 |

index > frame1 > frame1-1

7 | 8 | 9 | -------------------------------------------------------------------------------- /test/lib/www/frameset/frame1-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | frame1-2 4 | 5 | 6 |

index > frame1 > frame1-2

7 | 8 | 9 | -------------------------------------------------------------------------------- /test/lib/www/frameset/frame1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | frame1 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/lib/www/frameset/frame2-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | frame2-1 4 | 5 | 6 |

index > frame2 > frame2-1

7 | 8 | 9 | -------------------------------------------------------------------------------- /test/lib/www/frameset/frame2-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | frame2-2 4 | 5 | 6 |

index > frame2 > frame2-2

7 | 8 | 9 | -------------------------------------------------------------------------------- /test/lib/www/frameset/frame2-3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | frame2-3 4 | 5 | 6 |

index > frame2 > frame2-3

7 | 8 | 9 | -------------------------------------------------------------------------------- /test/lib/www/frameset/frame2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | frame2 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/lib/www/frameset/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | index 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/lib/www/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello 4 | 5 | 6 |

Hello, world!

7 | 8 | 9 | -------------------------------------------------------------------------------- /test/lib/www/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/lib/www/includejs.js: -------------------------------------------------------------------------------- 1 | function getTitle () { 2 | return document.title; 3 | } 4 | -------------------------------------------------------------------------------- /test/lib/www/includejs1.html: -------------------------------------------------------------------------------- 1 | 2 | i am includejs one 3 | -------------------------------------------------------------------------------- /test/lib/www/includejs2.html: -------------------------------------------------------------------------------- 1 | 2 | i am includejs two 3 | -------------------------------------------------------------------------------- /test/lib/www/js-infinite-loop.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/lib/www/load-images.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | logo 7 | phantomjs 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/lib/www/logo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Show logo 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/lib/www/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/test/lib/www/logo.png -------------------------------------------------------------------------------- /test/lib/www/missing-img.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Missing image 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/lib/www/navigation/dest.html: -------------------------------------------------------------------------------- 1 | 2 | DEST 3 | -------------------------------------------------------------------------------- /test/lib/www/navigation/index.html: -------------------------------------------------------------------------------- 1 | 2 | INDEX 3 | -------------------------------------------------------------------------------- /test/lib/www/phantomjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/test/lib/www/phantomjs.png -------------------------------------------------------------------------------- /test/lib/www/regression/pjs-10690/Windsong.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/test/lib/www/regression/pjs-10690/Windsong.ttf -------------------------------------------------------------------------------- /test/lib/www/regression/pjs-10690/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'WindsongRegular'; 3 | src: url("Windsong.ttf") format("truetype"); 4 | } 5 | h1 { 6 | font: 90px/98px "WindsongRegular", Arial, sans-serif; 7 | } 8 | -------------------------------------------------------------------------------- /test/lib/www/regression/pjs-10690/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Hello World

8 | 9 | 10 | -------------------------------------------------------------------------------- /test/lib/www/regression/pjs-13551/child1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /test/lib/www/regression/pjs-13551/child1a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | -------------------------------------------------------------------------------- /test/lib/www/regression/pjs-13551/child2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 |

success

10 | -------------------------------------------------------------------------------- /test/lib/www/regression/pjs-13551/closing-parent.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 23 | 24 | -------------------------------------------------------------------------------- /test/lib/www/regression/pjs-13551/reloading-parent.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | 23 | -------------------------------------------------------------------------------- /test/lib/www/regression/webkit-60448.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Test passes if it does not crash. 4 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /test/lib/www/render/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/test/lib/www/render/image.jpg -------------------------------------------------------------------------------- /test/lib/www/render/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /test/lib/www/status.py: -------------------------------------------------------------------------------- 1 | import cStringIO as StringIO 2 | import urlparse 3 | 4 | def html_esc(s): 5 | return s.replace('&','&').replace('<','<').replace('>','>') 6 | 7 | def handle_request(req): 8 | url = urlparse.urlparse(req.path) 9 | headers = [] 10 | body = "" 11 | 12 | try: 13 | query = urlparse.parse_qsl(url.query, strict_parsing=True) 14 | status = None 15 | for key, value in query: 16 | if key == 'status': 17 | if status is not None: 18 | raise ValueError("status can only be specified once") 19 | status = int(value) 20 | elif key == 'Content-Type' or key == 'Content-Length': 21 | raise ValueError("cannot override " + key) 22 | else: 23 | headers.append((key, value)) 24 | 25 | if status is None: 26 | status = 200 27 | 28 | body = "

Status: {}

".format(status) 29 | if headers: 30 | body += "
"
31 |             for key, value in headers:
32 |                 body += html_esc("{}: {}\n".format(key, value))
33 |             body += "
" 34 | 35 | except Exception as e: 36 | try: 37 | status = int(url.query) 38 | body = "

Status: {}

".format(status) 39 | except: 40 | status = 400 41 | body = "

Status: 400

" 42 | body += "
" + html_esc(str(e)) + "
" 43 | 44 | req.send_response(status) 45 | req.send_header('Content-Type', 'text/html') 46 | req.send_header('Content-Length', str(len(body))) 47 | for key, value in headers: 48 | req.send_header(key, value) 49 | req.end_headers() 50 | return StringIO.StringIO(body) 51 | -------------------------------------------------------------------------------- /test/lib/www/user-agent.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | User Agent 4 | 5 | 6 |

User agent is: Unknown.

7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/manual/standards/ecma-test262.js: -------------------------------------------------------------------------------- 1 | // Launch the official test suite for ECMA-262 2 | 3 | var webpage = require('webpage'); 4 | 5 | page = webpage.create(); 6 | page.onError = function() {}; 7 | 8 | page.open('http://test262.ecmascript.org/', function() { 9 | page.evaluate(function() { $('a#run').click(); }); 10 | page.evaluate(function() { $('img#btnRunAll').click(); }); 11 | 12 | function monitor() { 13 | 14 | var data = page.evaluate(function() { 15 | return { 16 | ran: $('#totalCounter').text(), 17 | total: $('#testsToRun').text(), 18 | pass: $('#Pass').text(), 19 | fail: $('#Fail').text(), 20 | progress: $('div#progressbar').text() 21 | }; 22 | }); 23 | 24 | console.log('Tests: ', data.ran, 'of', data.total, 25 | ' Pass:', data.pass, ' Fail:', data.fail); 26 | 27 | if (data.progress.indexOf('complete') > 0) { 28 | page.render('report.png'); 29 | phantom.exit(); 30 | } else { 31 | setTimeout(monitor, 1000); 32 | } 33 | } 34 | 35 | setTimeout(monitor, 0); 36 | }); 37 | -------------------------------------------------------------------------------- /test/module/child_process/basics.js: -------------------------------------------------------------------------------- 1 | // Test basic child process functionality 2 | // 3 | 4 | var fs = require('fs'); 5 | var process = require('child_process'); 6 | 7 | var ECHO_SCRIPT = fs.join(TEST_DIR, 'lib', 'fixtures', 'echo.py'); 8 | var CAT_SCRIPT = fs.join(TEST_DIR, 'lib', 'fixtures', 'cat.py'); 9 | 10 | 11 | async_test(function(){ 12 | var text = "hello"; 13 | var p = process.spawn(PYTHON, [ECHO_SCRIPT, text]); 14 | var out = ''; 15 | p.stdout.on('data', function(data) { out += data; }); 16 | p.on('exit', this.step_func_done( 17 | function(exitCode) { 18 | assert_equals(exitCode, 0); 19 | assert_equals(out, text); 20 | })); 21 | }, "call a simple subprocess"); 22 | 23 | async_test(function(){ 24 | var text = "hello"; 25 | var process = require('child_process'); 26 | var p = process.spawn(PYTHON, [CAT_SCRIPT]); 27 | var out = ''; 28 | p.stdout.on('data', function(data) { out += data; }); 29 | p.on('exit', this.step_func_done( 30 | function(exitCode) { 31 | assert_equals(exitCode, 0); 32 | assert_equals(out, text); 33 | })); 34 | p.stdin.write(text); 35 | p.stdin.close(); 36 | }, "call a subprocess that reads input"); 37 | -------------------------------------------------------------------------------- /test/module/cookiejar/cookiejar.js: -------------------------------------------------------------------------------- 1 | var cookie0 = { 2 | 'name': 'Valid-Cookie-Name', 3 | 'value': 'Valid-Cookie-Value', 4 | 'domain': 'localhost', 5 | 'path': '/foo', 6 | 'httponly': true, 7 | 'secure': false 8 | }; 9 | var cookie1 = { 10 | 'name': 'Valid-Cookie-Name-1', 11 | 'value': 'Valid-Cookie-Value', 12 | 'domain': 'localhost', 13 | 'path': '/foo', 14 | 'httponly': true, 15 | 'secure': false 16 | }; 17 | var cookie2 = { 18 | 'name': 'Valid-Cookie-Name-2', 19 | 'value': 'Valid-Cookie-Value', 20 | 'domain': 'localhost', 21 | 'path': '/foo', 22 | 'httponly': true, 23 | 'secure': false 24 | }; 25 | var cookies = [{ 26 | 'name': 'Valid-Cookie-Name', 27 | 'value': 'Valid-Cookie-Value', 28 | 'domain': 'localhost', 29 | 'path': '/foo', 30 | 'httponly': true, 31 | 'secure': false 32 | },{ 33 | 'name': 'Valid-Cookie-Name-Sec', 34 | 'value': 'Valid-Cookie-Value-Sec', 35 | 'domain': 'localhost', 36 | 'path': '/foo', 37 | 'httponly': true, 38 | 'secure': false, 39 | 'expires': new Date().getTime() + 3600 //< expires in 1h 40 | }]; 41 | 42 | var cookiejar, jar1, jar2; 43 | setup(function () { 44 | cookiejar = require('cookiejar'); 45 | jar1 = cookiejar.create(); 46 | jar2 = cookiejar.create(); 47 | }); 48 | 49 | test(function () { 50 | assert_type_of(jar1, 'object'); 51 | assert_not_equals(jar1, null); 52 | assert_type_of(jar1.cookies, 'object'); 53 | 54 | assert_type_of(jar1.addCookie, 'function'); 55 | assert_type_of(jar1.deleteCookie, 'function'); 56 | assert_type_of(jar1.clearCookies, 'function'); 57 | }, "cookie jar properties"); 58 | 59 | test(function () { 60 | assert_equals(jar1.cookies.length, 0); 61 | 62 | var isAdded = jar1.addCookie(cookie0); 63 | assert_equals(isAdded, true); 64 | assert_equals(jar1.cookies.length, 1); 65 | 66 | jar1.deleteCookie('Valid-Cookie-Name'); 67 | assert_equals(jar1.cookies.length, 0); 68 | }, "adding and removing cookies"); 69 | 70 | test(function () { 71 | assert_equals(jar1.cookies.length, 0); 72 | 73 | jar1.cookies = cookies; 74 | assert_equals(jar1.cookies.length, 2); 75 | 76 | jar1.clearCookies(); 77 | assert_equals(jar1.cookies.length, 0); 78 | }, "setting and clearing a cookie jar"); 79 | 80 | test(function () { 81 | var isAdded = jar1.addCookie(cookie1); 82 | assert_equals(isAdded, true); 83 | assert_equals(jar1.cookies.length, 1); 84 | assert_equals(jar2.cookies.length, 0); 85 | 86 | isAdded = jar2.addCookie(cookie2); 87 | assert_equals(isAdded, true); 88 | var isRemoved = jar1.deleteCookie('Valid-Cookie-Name-1'); 89 | assert_equals(isRemoved, true); 90 | assert_equals(jar1.cookies.length, 0); 91 | assert_equals(jar2.cookies.length, 1); 92 | 93 | jar1.close(); 94 | jar2.close(); 95 | 96 | }, "cookie jar isolation"); 97 | -------------------------------------------------------------------------------- /test/module/cookiejar/to-map.js: -------------------------------------------------------------------------------- 1 | var cookies = { 2 | 'beforeExpires': { 3 | 'name': 'beforeExpires', 4 | 'value': 'expireValue', 5 | 'domain': '.abc.com', 6 | 'path': '/', 7 | 'httponly': false, 8 | 'secure': false, 9 | 'expires': 'Tue, 10 Jun 2025 12:28:29 GMT' 10 | }, 11 | 'noExpiresDate': { 12 | 'name': 'noExpiresDate', 13 | 'value': 'value', 14 | 'domain': '.abc.com', 15 | 'path': '/', 16 | 'httponly': false, 17 | 'secure': false, 18 | 'expires': null 19 | }, 20 | 'afterExpires': { 21 | 'name': 'afterExpires', 22 | 'value': 'value', 23 | 'domain': '.abc.com', 24 | 'path': '/', 25 | 'httponly': false, 26 | 'secure': false, 27 | 'expires': 'Mon, 10 Jun 2024 12:28:29 GMT' 28 | } 29 | }; 30 | 31 | test(function () { 32 | var i, c, d, prop; 33 | for (i in cookies) { 34 | if (!cookies.hasOwnProperty(i)) continue; 35 | phantom.addCookie(cookies[i]); 36 | } 37 | for (i in phantom.cookies) { 38 | d = phantom.cookies[i]; 39 | c = cookies[d.name]; 40 | for (prop in c) { 41 | if (!c.hasOwnProperty(prop)) continue; 42 | if (c[prop] === null) { 43 | assert_no_property(d, prop); 44 | } else { 45 | assert_own_property(d, prop); 46 | assert_equals(c[prop], d[prop]); 47 | } 48 | } 49 | } 50 | 51 | }, "optional cookie properties should not leak"); 52 | -------------------------------------------------------------------------------- /test/module/fs/paths.js: -------------------------------------------------------------------------------- 1 | 2 | var fs = require('fs'); 3 | var system = require('system'); 4 | 5 | var TEST_DIR = "testdir", 6 | TEST_FILE = "testfile", 7 | START_CWD = fs.workingDirectory; 8 | 9 | test(function () { 10 | assert_is_true(fs.makeDirectory(TEST_DIR)); 11 | this.add_cleanup(function () { fs.removeTree(TEST_DIR); }); 12 | 13 | assert_is_true(fs.changeWorkingDirectory(TEST_DIR)); 14 | this.add_cleanup(function () { fs.changeWorkingDirectory(START_CWD); }); 15 | 16 | fs.write(TEST_FILE, TEST_FILE, "w"); 17 | var suffix = fs.join("", TEST_DIR, TEST_FILE), 18 | abs = fs.absolute(".." + suffix), 19 | lastIndex = abs.lastIndexOf(suffix); 20 | 21 | assert_not_equals(lastIndex, -1); 22 | assert_equals(lastIndex + suffix.length, abs.length); 23 | 24 | }, "manipulation of current working directory"); 25 | 26 | test(function () { 27 | 28 | fs.copyTree(phantom.libraryPath, TEST_DIR); 29 | this.add_cleanup(function () { fs.removeTree(TEST_DIR); }); 30 | 31 | assert_deep_equals(fs.list(phantom.libraryPath), fs.list(TEST_DIR)); 32 | 33 | }, "copying a directory tree"); 34 | 35 | test(function () { 36 | assert_type_of(fs.readLink, 'function'); 37 | // TODO: test the actual functionality once we can create symlinks. 38 | }, "fs.readLink exists"); 39 | 40 | generate_tests(function fs_join_test (parts, expected) { 41 | var actual = fs.join.apply(null, parts); 42 | assert_equals(actual, expected); 43 | }, [ 44 | [ "fs.join: []", [], "." ], 45 | [ "fs.join: nonsense", [[], null], "." ], 46 | [ "fs.join: 1 element", [""], "." ], 47 | [ "fs.join: 2 elements", ["", "a"], "/a" ], 48 | [ "fs.join: 3 elements", ["a", "b", "c"], "a/b/c" ], 49 | [ "fs.join: 4 elements", ["", "a", "b", "c"], "/a/b/c" ], 50 | [ "fs.join: empty elements", ["", "a", "", "b", "", "c"], "/a/b/c" ], 51 | [ "fs.join: empty elements 2", ["a", "", "b", "", "c"], "a/b/c" ] 52 | ]); 53 | 54 | generate_tests(function fs_split_test (input, expected) { 55 | var path = input.join(fs.separator); 56 | var actual = fs.split(path); 57 | assert_deep_equals(actual, expected); 58 | }, [ 59 | [ "fs.split: absolute", 60 | ["", "a", "b", "c", "d"], ["", "a", "b", "c", "d"] ], 61 | [ "fs.split: absolute, trailing", 62 | ["", "a", "b", "c", "d", ""], ["", "a", "b", "c", "d"] ], 63 | [ "fs.split: non-absolute", 64 | ["a", "b", "c", "d"], ["a", "b", "c", "d"] ], 65 | [ "fs.split: non-absolute, trailing", 66 | ["a", "b", "c", "d", ""], ["a", "b", "c", "d"] ], 67 | [ "fs.split: repeated separators", 68 | ["a", "", "", "", 69 | "b", "", 70 | "c", "", "", 71 | "d", "", "", ""], ["a", "b", "c", "d"] ] 72 | ]); 73 | -------------------------------------------------------------------------------- /test/module/system/stdin.js: -------------------------------------------------------------------------------- 1 | //! stdin: Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich 2 | //! stdin: いろはにほへとちりぬるをわかよたれそつねならむうゐのおくやまけふこえてあさきゆめみしゑひもせす 3 | 4 | //^ first line: pangram in German 5 | //^ second line: pan+isogram in hiragana (the Iroha) 6 | 7 | var stdin; 8 | setup(function () { stdin = require("system").stdin; }); 9 | 10 | test(function () { 11 | assert_equals(stdin.readLine(), 12 | "Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich"); 13 | }, "input line one (German)"); 14 | 15 | test(function () { 16 | assert_equals(stdin.readLine(), 17 | "いろはにほへとちりぬるをわかよたれそつねならむうゐのおくやまけふこえてあさきゆめみしゑひもせす"); 18 | }, "input line two (Japanese)"); 19 | 20 | test(function () { 21 | assert_equals(stdin.readLine(), ""); 22 | }, "input line three (EOF)"); 23 | -------------------------------------------------------------------------------- /test/module/system/stdout-err.js: -------------------------------------------------------------------------------- 1 | //! no-harness 2 | //! expect-stdout: Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich 3 | //! expect-stderr: いろはにほへとちりぬるをわかよたれそつねならむうゐのおくやまけふこえてあさきゆめみしゑひもせす 4 | 5 | //^ stdout: pangram in German 6 | //^ stderr: pan+isogram in hiragana (the Iroha) 7 | 8 | phantom.onError = function () { phantom.exit(1); }; 9 | 10 | var sys = require("system"); 11 | 12 | sys.stdout.write("Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich\n"); 13 | sys.stderr.write("いろはにほへとちりぬるをわかよたれそつねならむうゐのおくやまけふこえてあさきゆめみしゑひもせす"); 14 | phantom.exit(0); 15 | -------------------------------------------------------------------------------- /test/module/system/system.js: -------------------------------------------------------------------------------- 1 | var system = require('system'); 2 | 3 | test(function () { 4 | assert_type_of(system, 'object'); 5 | assert_not_equals(system, null); 6 | }, "system object"); 7 | 8 | test(function () { 9 | assert_own_property(system, 'pid'); 10 | assert_type_of(system.pid, 'number'); 11 | assert_greater_than(system.pid, 0); 12 | }, "system.pid"); 13 | 14 | test(function () { 15 | assert_own_property(system, 'isSSLSupported'); 16 | assert_type_of(system.isSSLSupported, 'boolean'); 17 | assert_equals(system.isSSLSupported, true); 18 | }, "system.isSSLSupported"); 19 | 20 | test(function () { 21 | assert_own_property(system, 'args'); 22 | assert_type_of(system.args, 'object'); 23 | assert_instance_of(system.args, Array); 24 | assert_greater_than_equal(system.args.length, 1); 25 | 26 | // args[0] will be the test harness. 27 | assert_regexp_match(system.args[0], /\btestharness\.js$/); 28 | }, "system.args"); 29 | 30 | test(function () { 31 | assert_own_property(system, 'env'); 32 | assert_type_of(system.env, 'object'); 33 | }, "system.env"); 34 | 35 | test(function () { 36 | assert_own_property(system, 'platform'); 37 | assert_type_of(system.platform, 'string'); 38 | assert_equals(system.platform, 'phantomjs'); 39 | }, "system.platform"); 40 | 41 | test(function () { 42 | assert_own_property(system, 'os'); 43 | assert_type_of(system.os, 'object'); 44 | 45 | assert_type_of(system.os.architecture, 'string'); 46 | assert_type_of(system.os.name, 'string'); 47 | assert_type_of(system.os.version, 'string'); 48 | 49 | if (system.os.name === 'mac') { 50 | // release is x.y.z with x = 10 for Snow Leopard and 14 for Yosemite 51 | assert_type_of(system.os.release, 'string'); 52 | assert_greater_than_equal(parseInt(system.os.release, 10), 10); 53 | } 54 | }, "system.os"); 55 | 56 | test(function () { 57 | assert_type_of(system.stdin, 'object'); 58 | assert_type_of(system.stdin.read, 'function'); 59 | assert_type_of(system.stdin.readLine, 'function'); 60 | assert_type_of(system.stdin.close, 'function'); 61 | }, "system.stdin"); 62 | 63 | test(function () { 64 | assert_type_of(system.stdout, 'object'); 65 | assert_type_of(system.stdout.write, 'function'); 66 | assert_type_of(system.stdout.writeLine, 'function'); 67 | assert_type_of(system.stdout.flush, 'function'); 68 | assert_type_of(system.stdout.close, 'function'); 69 | }, "system.stdout"); 70 | 71 | test(function () { 72 | assert_type_of(system.stderr, 'object'); 73 | assert_type_of(system.stderr.write, 'function'); 74 | assert_type_of(system.stderr.writeLine, 'function'); 75 | assert_type_of(system.stderr.flush, 'function'); 76 | assert_type_of(system.stderr.close, 'function'); 77 | }, "system.stderr"); 78 | -------------------------------------------------------------------------------- /test/module/webpage/abort-network-request.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | async_test(function () { 4 | var page = webpage.create(); 5 | var abortCount = 0; 6 | var errorCount = 0; 7 | var abortedIds = {}; 8 | var urlToBlockRegExp = /logo\.png$/i; 9 | 10 | page.onResourceRequested = this.step_func(function(requestData, request) { 11 | assert_type_of(request, 'object'); 12 | assert_type_of(request.abort, 'function'); 13 | if (urlToBlockRegExp.test(requestData.url)) { 14 | request.abort(); 15 | ++abortCount; 16 | abortedIds[requestData.id] = 1; 17 | } 18 | }); 19 | page.onResourceError = this.step_func(function(error) { 20 | // We can't match up errors to requests by URL because error.url will 21 | // be the empty string in this case. FIXME. 22 | assert_own_property(abortedIds, error.id); 23 | ++errorCount; 24 | }); 25 | page.onResourceReceived = this.step_func(function(response) { 26 | assert_regexp_not_match(response.url, urlToBlockRegExp); 27 | }); 28 | 29 | page.open(TEST_HTTP_BASE + 'logo.html', 30 | this.step_func_done(function (status) { 31 | assert_equals(status, 'success'); 32 | assert_equals(abortCount, 1); 33 | assert_equals(errorCount, 1); 34 | })); 35 | 36 | }, "can abort network requests"); 37 | -------------------------------------------------------------------------------- /test/module/webpage/add-header.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | var webpage = require('webpage'); 3 | 4 | // NOTE: HTTP header names are case-insensitive. Our test server 5 | // returns the name in lowercase. 6 | 7 | var page = webpage.create(); 8 | assert_type_of(page.customHeaders, 'object'); 9 | assert_deep_equals(page.customHeaders, {}); 10 | 11 | page.onResourceRequested = this.step_func(function(requestData, request) { 12 | assert_type_of(request.setHeader, 'function'); 13 | request.setHeader('CustomHeader', 'CustomValue'); 14 | }); 15 | page.open(TEST_HTTP_BASE + 'echo', this.step_func_done(function (status) { 16 | var json, headers; 17 | assert_equals(status, 'success'); 18 | json = JSON.parse(page.plainText); 19 | headers = json.headers; 20 | assert_own_property(headers, 'customheader'); 21 | assert_equals(headers.customheader, 'CustomValue'); 22 | })); 23 | 24 | }, "add custom headers in onResourceRequested"); 25 | -------------------------------------------------------------------------------- /test/module/webpage/callback.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var page = require('webpage').create(); 3 | 4 | var msgA = "a", 5 | msgB = "b", 6 | result, 7 | expected = msgA + msgB; 8 | page.onCallback = function(a, b) { 9 | return a + b; 10 | }; 11 | result = page.evaluate(function(a, b) { 12 | return window.callPhantom(a, b); 13 | }, msgA, msgB); 14 | 15 | assert_equals(result, expected); 16 | }, "page.onCallback"); 17 | -------------------------------------------------------------------------------- /test/module/webpage/capture-content.js: -------------------------------------------------------------------------------- 1 | var content; 2 | setup(function () { 3 | var fs = require('fs'); 4 | content = fs.read(fs.join(TEST_DIR, "lib/www/hello.html")); 5 | }); 6 | 7 | // XFAIL: This feature had to be backed out for breaking WebSockets. 8 | async_test(function () { 9 | var page = require('webpage').create(); 10 | var lastChunk = ""; 11 | var bodySize = 0; 12 | page.captureContent = ['.*']; 13 | // Not a step function because it may be called several times 14 | // and doesn't need to make assertions. 15 | page.onResourceReceived = function (resource) { 16 | lastChunk = resource.body; 17 | bodySize = resource.bodySize; 18 | }; 19 | page.open(TEST_HTTP_BASE + "hello.html", 20 | this.step_func_done(function (status) { 21 | assert_equals(status, "success"); 22 | assert_equals(bodySize, content.length); 23 | assert_equals(lastChunk, content); 24 | })); 25 | 26 | }, "onResourceReceived sees the body if captureContent is activated", 27 | { expected_fail: true } 28 | ); 29 | 30 | async_test(function () { 31 | var page = require('webpage').create(); 32 | var lastChunk = ""; 33 | var bodySize = 0; 34 | page.captureContent = ['/some/other/url']; 35 | // Not a step function because it may be called several times 36 | // and doesn't need to make assertions. 37 | page.onResourceReceived = function (resource) { 38 | lastChunk = resource.body; 39 | bodySize = resource.bodySize; 40 | }; 41 | page.open(TEST_HTTP_BASE + "hello.html", 42 | this.step_func_done(function (status) { 43 | assert_equals(status, "success"); 44 | assert_equals(bodySize, 0); 45 | assert_equals(lastChunk, ""); 46 | })); 47 | }, "onResourceReceived doesn't see the body if captureContent doesn't match"); 48 | -------------------------------------------------------------------------------- /test/module/webpage/change-request-encoded-url.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | async_test(function () { 4 | var page = webpage.create(); 5 | 6 | var url = TEST_HTTP_BASE + "cdn-cgi/pe/bag?r%5B%5D="+ 7 | "http%3A%2F%2Fwww.example.org%2Fcdn-cgi%2Fnexp%2F"+ 8 | "abv%3D927102467%2Fapps%2Fabetterbrowser.js"; 9 | var receivedUrl; 10 | 11 | page.onResourceRequested = this.step_func(function(requestData, request) { 12 | request.changeUrl(requestData.url); 13 | }); 14 | 15 | page.onResourceReceived = this.step_func(function(data) { 16 | if (data.stage === 'end') { 17 | receivedUrl = data.url; 18 | } 19 | }); 20 | 21 | page.open(url, this.step_func_done(function (status) { 22 | assert_equals(status, 'success'); 23 | assert_equals(receivedUrl, url); 24 | })); 25 | 26 | }, "encoded URLs properly round-trip through request.changeUrl"); 27 | -------------------------------------------------------------------------------- /test/module/webpage/change-request-url.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | async_test(function () { 4 | 5 | var page = webpage.create(); 6 | var urlToChange = TEST_HTTP_BASE + 'logo.png'; 7 | var alternativeUrl = TEST_HTTP_BASE + 'phantomjs-logo.gif'; 8 | var startStage = 0; 9 | var endStage = 0; 10 | 11 | page.onResourceRequested = this.step_func(function(requestData, request) { 12 | if (requestData.url === urlToChange) { 13 | assert_type_of(request, 'object'); 14 | assert_type_of(request.changeUrl, 'function'); 15 | request.changeUrl(alternativeUrl); 16 | } 17 | }); 18 | 19 | page.onResourceReceived = this.step_func(function(data) { 20 | if (data.url === alternativeUrl && data.stage === 'start') { 21 | ++startStage; 22 | } 23 | if (data.url === alternativeUrl && data.stage === 'end') { 24 | ++endStage; 25 | } 26 | }); 27 | 28 | page.open(TEST_HTTP_BASE + 'logo.html', 29 | this.step_func_done(function (status) { 30 | assert_equals(status, 'success'); 31 | assert_equals(startStage, 1); 32 | assert_equals(endStage, 1); 33 | 34 | // The page HTML should still refer to the original image. 35 | assert_regexp_match(page.content, /logo\.png/); 36 | assert_regexp_not_match(page.content, /logo\.gif/); 37 | })); 38 | 39 | }, "request.changeUrl"); 40 | -------------------------------------------------------------------------------- /test/module/webpage/cjk-text-codecs.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | function test_one(text) { 4 | var t = async_test(text.codec); 5 | t.step(function () { 6 | var page = webpage.create(); 7 | page.open(text.url, t.step_func_done(function () { 8 | var decodedText = page.evaluate(function() { 9 | return document.querySelector('pre').innerText; 10 | }); 11 | var regex = '^' + text.reference + '$'; 12 | assert_regexp_match(text.reference, new RegExp(regex)); 13 | })); 14 | }); 15 | } 16 | 17 | function Text(codec, base64, reference) { 18 | this.codec = codec; 19 | this.base64 = base64; 20 | this.reference = reference; 21 | this.url = 'data:text/plain;charset=' + this.codec + 22 | ';base64,' + this.base64; 23 | } 24 | 25 | [ 26 | new Text('Shift_JIS', 'g3SDQIOTg2eDgA==', 'ファントム'), 27 | new Text('EUC-JP', 'pdWloaXzpcil4A0K', 'ファントム'), 28 | new Text('ISO-2022-JP', 'GyRCJVUlISVzJUglYBsoQg0K', 'ファントム'), 29 | new Text('Big5', 'pNu2SA0K', '幻象'), 30 | new Text('GBK', 'u8PP8w0K', '幻象'), 31 | new Text('EUC-KR', 'yK+/tQ==', '환영'), 32 | ] 33 | .forEach(test_one); 34 | -------------------------------------------------------------------------------- /test/module/webpage/clip-rect.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | test(function () { 4 | var defaultPage = webpage.create(); 5 | assert_deep_equals(defaultPage.clipRect, {height:0,left:0,top:0,width:0}); 6 | }, "default page.clipRect"); 7 | 8 | test(function () { 9 | var options = { 10 | clipRect: { 11 | height: 100, 12 | left: 10, 13 | top: 20, 14 | width: 200 15 | } 16 | }; 17 | var customPage = webpage.create(options); 18 | assert_deep_equals(customPage.clipRect, options.clipRect); 19 | }, "custom page.clipRect"); 20 | -------------------------------------------------------------------------------- /test/module/webpage/construction-with-options.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var opts = {}, 3 | page = new WebPage(opts); 4 | assert_type_of(page, 'object'); 5 | assert_not_equals(page, null); 6 | }, "webpage constructor accepts an opts object"); 7 | 8 | async_test(function () { 9 | var opts = { 10 | onConsoleMessage: this.step_func_done(function (msg) { 11 | assert_equals(msg, "test log"); 12 | }) 13 | }; 14 | var page = new WebPage(opts); 15 | assert_equals(page.onConsoleMessage, opts.onConsoleMessage); 16 | page.evaluate(function () {console.log('test log');}); 17 | 18 | }, "specifying onConsoleMessage with opts"); 19 | 20 | async_test(function () { 21 | var page_opened = false; 22 | var opts = { 23 | onLoadStarted: this.step_func_done(function (msg) { 24 | assert_is_true(page_opened); 25 | }) 26 | }; 27 | var page = new WebPage(opts); 28 | assert_equals(page.onLoadStarted, opts.onLoadStarted); 29 | page_opened = true; 30 | page.open("about:blank"); 31 | 32 | }, "specifying onLoadStarted with opts"); 33 | 34 | async_test(function () { 35 | var page_opened = false; 36 | var opts = { 37 | onLoadFinished: this.step_func_done(function (msg) { 38 | assert_is_true(page_opened); 39 | }) 40 | }; 41 | var page = new WebPage(opts); 42 | assert_equals(page.onLoadFinished, opts.onLoadFinished); 43 | page_opened = true; 44 | page.open("about:blank"); 45 | 46 | }, "specifying onLoadFinished with opts"); 47 | 48 | // FIXME: Actually test that the timeout is effective. 49 | test(function () { 50 | var opts = { 51 | settings: { 52 | timeout: 100 // time in ms 53 | } 54 | }; 55 | var page = new WebPage(opts); 56 | assert_equals(page.settings.timeout, opts.settings.timeout); 57 | 58 | }, "specifying timeout with opts"); 59 | -------------------------------------------------------------------------------- /test/module/webpage/contextclick-event.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var page = require('webpage').create(); 3 | 4 | page.evaluate(function() { 5 | window.addEventListener('contextmenu', function(event) { 6 | window.loggedEvent = window.loggedEvent || {}; 7 | window.loggedEvent.contextmenu = event; 8 | }, false); 9 | }); 10 | page.sendEvent('contextmenu', 42, 217); 11 | 12 | var event = page.evaluate(function() { 13 | return window.loggedEvent; 14 | }); 15 | assert_equals(event.contextmenu.clientX, 42); 16 | assert_equals(event.contextmenu.clientY, 217); 17 | 18 | // click with modifier key 19 | page.evaluate(function() { 20 | window.addEventListener('contextmenu', function(event) { 21 | window.loggedEvent = window.loggedEvent || {}; 22 | window.loggedEvent.contextmenu = event; 23 | }, false); 24 | }); 25 | page.sendEvent('contextmenu', 100, 100, 'left', page.event.modifier.shift); 26 | 27 | var event = page.evaluate(function() { 28 | return window.loggedEvent.contextmenu; 29 | }); 30 | assert_is_true(event.shiftKey); 31 | 32 | }, "context click events"); 33 | -------------------------------------------------------------------------------- /test/module/webpage/custom-headers.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | var webpage = require('webpage'); 3 | var page = webpage.create(); 4 | assert_type_of(page.customHeaders, 'object'); 5 | assert_deep_equals(page.customHeaders, {}); 6 | 7 | // NOTE: HTTP header names are case-insensitive. Our test server 8 | // returns the name in lowercase. 9 | page.customHeaders = { 10 | 'Custom-Key': 'Custom-Value', 11 | 'User-Agent': 'Overriden-UA', 12 | 'Referer': 'Overriden-Referer' 13 | }; 14 | page.open(TEST_HTTP_BASE + 'echo', this.step_func_done(function (status) { 15 | var json, headers; 16 | assert_equals(status, 'success'); 17 | json = JSON.parse(page.plainText); 18 | assert_type_of(json, 'object'); 19 | headers = json.headers; 20 | assert_type_of(headers, 'object'); 21 | 22 | assert_own_property(headers, 'custom-key'); 23 | assert_own_property(headers, 'user-agent'); 24 | assert_own_property(headers, 'referer'); 25 | assert_equals(headers['custom-key'], 'Custom-Value'); 26 | assert_equals(headers['user-agent'], 'Overriden-UA'); 27 | assert_equals(headers['referer'], 'Overriden-Referer'); 28 | })); 29 | 30 | }, "adding custom headers with page.customHeaders"); 31 | -------------------------------------------------------------------------------- /test/module/webpage/evaluate-broken-json.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var webpage = require('webpage'); 3 | var page = webpage.create(); 4 | 5 | // Hijack JSON.parse to something completely useless. 6 | page.content = ''; 7 | 8 | var result = page.evaluate(function(obj) { 9 | return obj.value * obj.value; 10 | }, { value: 4 }); 11 | 12 | assert_equals(result, 16); 13 | 14 | }, "page script should not interfere with page.evaluate"); 15 | -------------------------------------------------------------------------------- /test/module/webpage/file-upload.js: -------------------------------------------------------------------------------- 1 | 2 | // Note: uses various files in module/webpage as things to be uploaded. 3 | // Which files they are doesn't matter. 4 | 5 | var page; 6 | setup(function () { 7 | page = new WebPage(); 8 | page.content = 9 | '\n' + 10 | '\n' + 11 | '' + 12 | ''; 13 | page.uploadFile("#file", "file-upload.js"); 14 | page.uploadFile("#file2", "file-upload.js"); 15 | page.uploadFile("#file3", ["file-upload.js", "object.js"]); 16 | }); 17 | 18 | function test_one_elt(id, names) { 19 | var files = page.evaluate(function (id) { 20 | var elt = document.getElementById(id); 21 | var rv = []; 22 | for (var i = 0; i < elt.files.length; i++) { 23 | rv.push(elt.files[i].fileName); 24 | } 25 | return rv; 26 | }, id); 27 | assert_deep_equals(files, names); 28 | } 29 | 30 | generate_tests(test_one_elt, [ 31 | ["single upload single file", "file", ["file-upload.js"]], 32 | ["multiple upload single file", "file2", ["file-upload.js"]], 33 | ["multiple upload multiple file", "file3", ["file-upload.js", "object.js"]], 34 | ], { expected_fail: true }); 35 | 36 | async_test(function () { 37 | page.onFilePicker = this.step_func(function (oldFile) { 38 | assert_equals(oldFile, ""); 39 | return "no-plugin.js"; 40 | }); 41 | 42 | test_one_elt("file4", []); 43 | 44 | page.evaluate(function () { 45 | var fileUp = document.querySelector("#file4"); 46 | var ev = document.createEvent("MouseEvents"); 47 | ev.initEvent("click", true, true); 48 | fileUp.dispatchEvent(ev); 49 | }); 50 | 51 | setTimeout(this.step_func_done(function () { 52 | test_one_elt("file4", ["no-plugin.js"]); 53 | }, 0)); 54 | 55 | }, "page.onFilePicker", { expected_fail: true }); 56 | -------------------------------------------------------------------------------- /test/module/webpage/frame-switching-deprecated.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | var p = require("webpage").create(); 3 | 4 | function pageTitle(page) { 5 | return page.evaluate(function(){ 6 | return window.document.title; 7 | }); 8 | } 9 | 10 | function setPageTitle(page, newTitle) { 11 | page.evaluate(function(newTitle){ 12 | window.document.title = newTitle; 13 | }, newTitle); 14 | } 15 | 16 | function testFrameSwitchingDeprecated() { 17 | assert_equals(pageTitle(p), "index"); 18 | assert_equals(p.currentFrameName(), ""); 19 | assert_equals(p.childFramesCount(), 2); 20 | assert_deep_equals(p.childFramesName(), ["frame1", "frame2"]); 21 | setPageTitle(p, pageTitle(p) + "-visited"); 22 | 23 | assert_is_true(p.switchToChildFrame("frame1")); 24 | assert_equals(pageTitle(p), "frame1"); 25 | assert_equals(p.currentFrameName(), "frame1"); 26 | assert_equals(p.childFramesCount(), 2); 27 | assert_deep_equals(p.childFramesName(), ["frame1-1", "frame1-2"]); 28 | setPageTitle(p, pageTitle(p) + "-visited"); 29 | 30 | assert_is_true(p.switchToChildFrame("frame1-2")); 31 | assert_equals(pageTitle(p), "frame1-2"); 32 | assert_equals(p.currentFrameName(), "frame1-2"); 33 | assert_equals(p.childFramesCount(), 0); 34 | assert_deep_equals(p.childFramesName(), []); 35 | setPageTitle(p, pageTitle(p) + "-visited"); 36 | 37 | assert_is_true(p.switchToParentFrame()); 38 | assert_equals(pageTitle(p), "frame1-visited"); 39 | assert_equals(p.currentFrameName(), "frame1"); 40 | assert_equals(p.childFramesCount(), 2); 41 | assert_deep_equals(p.childFramesName(), ["frame1-1", "frame1-2"]); 42 | 43 | assert_is_true(p.switchToChildFrame(0)); 44 | assert_equals(pageTitle(p), "frame1-1"); 45 | assert_equals(p.currentFrameName(), "frame1-1"); 46 | assert_equals(p.childFramesCount(), 0); 47 | assert_deep_equals(p.childFramesName(), []); 48 | 49 | assert_equals(p.switchToMainFrame(), undefined); 50 | assert_equals(pageTitle(p), "index-visited"); 51 | assert_equals(p.currentFrameName(), ""); 52 | assert_equals(p.childFramesCount(), 2); 53 | assert_deep_equals(p.childFramesName(), ["frame1", "frame2"]); 54 | 55 | assert_is_true(p.switchToChildFrame("frame2")); 56 | assert_equals(pageTitle(p), "frame2"); 57 | assert_equals(p.currentFrameName(), "frame2"); 58 | assert_equals(p.childFramesCount(), 3); 59 | assert_deep_equals(p.childFramesName(), 60 | ["frame2-1", "frame2-2", "frame2-3"]); 61 | } 62 | 63 | p.open(TEST_HTTP_BASE + "frameset", this.step_func_done(function (s) { 64 | assert_equals(s, "success"); 65 | testFrameSwitchingDeprecated(); 66 | })); 67 | 68 | }, "frame switching deprecated API"); 69 | -------------------------------------------------------------------------------- /test/module/webpage/https-bad-cert.js: -------------------------------------------------------------------------------- 1 | //! no-snakeoil 2 | async_test(function () { 3 | // This loads the same page as https-good-cert.js, but does not 4 | // tell PhantomJS to trust the snakeoil certificate that the test 5 | // HTTPS server uses, so it should fail. 6 | 7 | var page = require('webpage').create(); 8 | var url = TEST_HTTPS_BASE; 9 | page.onResourceError = this.step_func(function (err) { 10 | assert_equals(err.url, url); 11 | assert_equals(err.errorString, "SSL handshake failed"); 12 | }); 13 | page.open(url, this.step_func_done(function (status) { 14 | assert_not_equals(status, "success"); 15 | })); 16 | }, "should fail to load an HTTPS webpage with a self-signed certificate"); 17 | -------------------------------------------------------------------------------- /test/module/webpage/https-good-cert.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | // This loads the same page as https-bad-cert.js; by default the 3 | // test suite tells PhantomJS to trust the snakeoil certificate 4 | // that the test HTTPS server uses, so it should succeed. 5 | 6 | var page = require('webpage').create(); 7 | var url = TEST_HTTPS_BASE; 8 | page.onResourceError = this.unreached_func(); 9 | page.open(url, this.step_func_done(function (status) { 10 | assert_equals(status, "success"); 11 | })); 12 | }, "loading an HTTPS webpage"); 13 | -------------------------------------------------------------------------------- /test/module/webpage/includejs.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | async_test(function () { 4 | var page = webpage.create(); 5 | page.open(TEST_HTTP_BASE + 'includejs1.html', 6 | this.step_func(function (status) { 7 | assert_equals(status, 'success'); 8 | page.includeJs(TEST_HTTP_BASE + 'includejs.js', 9 | this.step_func_done(function () { 10 | var title = page.evaluate('getTitle'); 11 | assert_equals(title, 'i am includejs one'); 12 | })); 13 | })); 14 | 15 | }, "including JS in a page"); 16 | 17 | async_test(function () { 18 | var page = webpage.create(); 19 | var already = false; 20 | page.open(TEST_HTTP_BASE + 'includejs1.html', 21 | this.step_func(function (status) { 22 | assert_equals(status, 'success'); 23 | page.includeJs(TEST_HTTP_BASE + 'includejs.js', 24 | this.step_func(function () { 25 | assert_is_false(already); 26 | already = true; 27 | var title = page.evaluate('getTitle'); 28 | assert_equals(title, 'i am includejs one'); 29 | page.open(TEST_HTTP_BASE + 'includejs2.html', 30 | this.step_func(function (status) { 31 | assert_equals(status, 'success'); 32 | page.includeJs(TEST_HTTP_BASE + 'includejs.js', 33 | this.step_func_done(function () { 34 | assert_is_true(already); 35 | var title = page.evaluate('getTitle'); 36 | assert_equals(title, 'i am includejs two'); 37 | })); 38 | })); 39 | })); 40 | })); 41 | 42 | }, "after-inclusion callbacks should fire only once"); 43 | -------------------------------------------------------------------------------- /test/module/webpage/keydown-event.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var webpage = require('webpage'); 3 | 4 | var page = webpage.create(); 5 | 6 | page.evaluate(function() { 7 | window.addEventListener('keydown', function(event) { 8 | window.loggedEvent = window.loggedEvent || []; 9 | window.loggedEvent.push(event); 10 | }, false); 11 | }); 12 | 13 | page.sendEvent('keydown', page.event.key.A); 14 | var loggedEvent = page.evaluate(function() { 15 | return window.loggedEvent; 16 | }); 17 | 18 | assert_equals(loggedEvent.length, 1); 19 | assert_equals(loggedEvent[0].which, page.event.key.A); 20 | }, "key-down events"); 21 | -------------------------------------------------------------------------------- /test/module/webpage/keypress-event.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var webpage = require('webpage'); 3 | 4 | var page = webpage.create(); 5 | 6 | page.evaluate(function() { 7 | window.addEventListener('keypress', function(event) { 8 | window.loggedEvent = window.loggedEvent || []; 9 | window.loggedEvent.push(event); 10 | }, false); 11 | }); 12 | 13 | page.sendEvent('keypress', page.event.key.C); 14 | var loggedEvent = page.evaluate(function() { 15 | return window.loggedEvent; 16 | }); 17 | 18 | assert_equals(loggedEvent.length, 1); 19 | assert_equals(loggedEvent[0].which, page.event.key.C); 20 | 21 | 22 | // Send keypress events to an input element and observe the effect. 23 | 24 | page.content = ''; 25 | page.evaluate(function() { 26 | document.querySelector('input').focus(); 27 | }); 28 | 29 | function getText() { 30 | return page.evaluate(function() { 31 | return document.querySelector('input').value; 32 | }); 33 | } 34 | 35 | page.sendEvent('keypress', page.event.key.A); 36 | assert_equals(getText(), 'A'); 37 | page.sendEvent('keypress', page.event.key.B); 38 | assert_equals(getText(), 'AB'); 39 | page.sendEvent('keypress', page.event.key.Backspace); 40 | assert_equals(getText(), 'A'); 41 | page.sendEvent('keypress', page.event.key.Backspace); 42 | assert_equals(getText(), ''); 43 | 44 | page.sendEvent('keypress', 'XYZ'); 45 | assert_equals(getText(), 'XYZ'); 46 | 47 | // Special character: A with umlaut 48 | page.sendEvent('keypress', 'ä'); 49 | assert_equals(getText(), 'XYZä'); 50 | 51 | // 0x02000000 is the Shift modifier. 52 | page.sendEvent('keypress', page.event.key.Home, null, null, 0x02000000); 53 | page.sendEvent('keypress', page.event.key.Delete); 54 | assert_equals(getText(), ''); 55 | 56 | // Cut and Paste 57 | // 0x04000000 is the Control modifier. 58 | page.sendEvent('keypress', 'ABCD'); 59 | assert_equals(getText(), 'ABCD'); 60 | page.sendEvent('keypress', page.event.key.Home, null, null, 0x02000000); 61 | page.sendEvent('keypress', 'x', null, null, 0x04000000); 62 | assert_equals(getText(), ''); 63 | page.sendEvent('keypress', 'v', null, null, 0x04000000); 64 | assert_equals(getText(), 'ABCD'); 65 | }, "key press events"); 66 | -------------------------------------------------------------------------------- /test/module/webpage/keyup-event.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var webpage = require('webpage'); 3 | 4 | var page = webpage.create(); 5 | 6 | page.evaluate(function() { 7 | window.addEventListener('keyup', function(event) { 8 | window.loggedEvent = window.loggedEvent || []; 9 | window.loggedEvent.push(event); 10 | }, false); 11 | }); 12 | 13 | page.sendEvent('keyup', page.event.key.B); 14 | var loggedEvent = page.evaluate(function() { 15 | return window.loggedEvent; 16 | }); 17 | 18 | assert_equals(loggedEvent.length, 1); 19 | assert_equals(loggedEvent[0].which, page.event.key.B); 20 | }, "key-up events"); 21 | -------------------------------------------------------------------------------- /test/module/webpage/load-images-no.js: -------------------------------------------------------------------------------- 1 | //! phantomjs: --load-images=no 2 | "use strict"; 3 | 4 | // Compiled for debug, this tests for leaks when not loading images. 5 | 6 | var url = TEST_HTTP_BASE + 'load-images.html'; 7 | 8 | async_test(function testLoadImagesNo () { 9 | var page = require('webpage').create(); 10 | 11 | var numImagesRequested = 0; 12 | var numImagesLoaded = 0; 13 | 14 | page.onResourceRequested = this.step_func(function (resource) { 15 | if (/\.png$/.test(resource.url)) ++numImagesRequested; 16 | }); 17 | 18 | page.onResourceReceived = this.step_func(function (resource) { 19 | if (resource.stage === 'end' && /\.png$/.test(resource.url)) ++numImagesLoaded; 20 | }); 21 | 22 | function checkImageCounts () 23 | { 24 | var imageCounts = page.evaluate (function countImages() { 25 | "use strict"; 26 | try 27 | { 28 | var images = document.getElementsByTagName('img'); 29 | var imageCounts = {}; 30 | imageCounts.numImages = images.length; 31 | imageCounts.numComplete = Array.prototype.reduce.call(images, function(n, image) { return n + (image.complete? 1 : 0); }, 0); 32 | return imageCounts; 33 | } 34 | catch(err) 35 | { 36 | return undefined; 37 | } 38 | }); 39 | assert_equals(imageCounts.numImages, 2); 40 | assert_equals(imageCounts.numComplete, 0); 41 | assert_equals(numImagesRequested, 0); 42 | assert_equals(numImagesLoaded, 0); 43 | } 44 | 45 | page.open(url, this.step_func_done (function pageOpened(status) { 46 | assert_equals(status, "success"); 47 | checkImageCounts(); 48 | page.release(); 49 | })); 50 | }, "load a page two images with --load-images=no"); 51 | -------------------------------------------------------------------------------- /test/module/webpage/load-images-yes.js: -------------------------------------------------------------------------------- 1 | //! phantomjs: --load-images=yes 2 | "use strict"; 3 | 4 | var url = TEST_HTTP_BASE + 'load-images.html'; 5 | 6 | async_test(function testLoadImagesYes () { 7 | var page = require('webpage').create(); 8 | 9 | var numImagesRequested = 0; 10 | var numImagesLoaded = 0; 11 | 12 | page.onResourceRequested = this.step_func(function (resource) { 13 | if (/\.png$/.test(resource.url)) ++numImagesRequested; 14 | }); 15 | 16 | page.onResourceReceived = this.step_func(function (resource) { 17 | if (resource.stage === 'end' && /\.png$/.test(resource.url)) ++numImagesLoaded; 18 | }); 19 | 20 | function checkImageCounts () 21 | { 22 | var imageCounts = page.evaluate (function countImages() { 23 | "use strict"; 24 | try 25 | { 26 | var images = document.getElementsByTagName('img'); 27 | var imageCounts = {}; 28 | imageCounts.numImages = images.length; 29 | imageCounts.numComplete = Array.prototype.reduce.call(images, function(n, image) { return n + (image.complete? 1 : 0); }, 0); 30 | return imageCounts; 31 | } 32 | catch(err) 33 | { 34 | return undefined; 35 | } 36 | }); 37 | assert_equals(imageCounts.numImages, 2); 38 | assert_equals(imageCounts.numComplete, 2); 39 | assert_equals(numImagesRequested, 2); 40 | assert_equals(numImagesLoaded, 2); 41 | } 42 | 43 | page.open(url, this.step_func_done (function pageOpened(status) { 44 | assert_equals(status, "success"); 45 | checkImageCounts(); 46 | page.release(); 47 | })); 48 | }, "load a page two images with --load-images=yes"); 49 | -------------------------------------------------------------------------------- /test/module/webpage/loading.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | var webpage = require('webpage'); 3 | var page = webpage.create(); 4 | 5 | assert_type_of(page, 'object'); 6 | assert_type_of(page.loading, 'boolean'); 7 | assert_type_of(page.loadingProgress, 'number'); 8 | 9 | assert_is_false(page.loading); 10 | assert_equals(page.loadingProgress, 0); 11 | 12 | page.open(TEST_HTTP_BASE + 'hello.html', 13 | this.step_func_done(function (status) { 14 | assert_equals(status, 'success'); 15 | assert_equals(page.loading, false); 16 | assert_equals(page.loadingProgress, 100); 17 | })); 18 | 19 | assert_is_true(page.loading); 20 | assert_greater_than(page.loadingProgress, 0); 21 | }, "page loading progress"); 22 | -------------------------------------------------------------------------------- /test/module/webpage/local-urls-disabled-iframe.js: -------------------------------------------------------------------------------- 1 | //! phantomjs: --web-security=no --local-url-access=no 2 | 3 | var webpage = require("webpage"); 4 | 5 | async_test(function () { 6 | var page = webpage.create(); 7 | var url = TEST_HTTP_BASE + "iframe.html#file:///nonexistent"; 8 | var rsErrorCalled = false; 9 | 10 | page.onResourceError = this.step_func(function (error) { 11 | rsErrorCalled = true; 12 | assert_equals(error.url, "file:///nonexistent"); 13 | assert_equals(error.errorCode, 301); 14 | assert_equals(error.errorString, 'Protocol "file" is unknown'); 15 | }); 16 | 17 | page.open(url, this.step_func_done(function () { 18 | assert_is_true(rsErrorCalled); 19 | })); 20 | 21 | }, 22 | "doesn't attempt to load a file: URL in an iframe with --local-url-access=no"); 23 | -------------------------------------------------------------------------------- /test/module/webpage/local-urls-disabled.js: -------------------------------------------------------------------------------- 1 | //! phantomjs: --local-url-access=no 2 | 3 | var webpage = require("webpage"); 4 | 5 | async_test(function () { 6 | var page = webpage.create(); 7 | var url = "file:///nonexistent"; 8 | var rsErrorCalled = false; 9 | 10 | page.onResourceError = this.step_func(function (error) { 11 | rsErrorCalled = true; 12 | assert_equals(error.url, url); 13 | assert_equals(error.errorCode, 301); 14 | assert_equals(error.errorString, 'Protocol "file" is unknown'); 15 | }); 16 | 17 | page.open(url, this.step_func_done(function () { 18 | assert_is_true(rsErrorCalled); 19 | })); 20 | 21 | }, "doesn't attempt to load a file: URL with --local-url-access=no"); 22 | -------------------------------------------------------------------------------- /test/module/webpage/local-urls-enabled-iframe.js: -------------------------------------------------------------------------------- 1 | //! phantomjs: --web-security=no --local-url-access=yes 2 | 3 | var webpage = require("webpage"); 4 | 5 | async_test(function () { 6 | var page = webpage.create(); 7 | var url = TEST_HTTP_BASE + "iframe.html#file:///nonexistent"; 8 | var rsErrorCalled = false; 9 | 10 | page.onResourceError = this.step_func(function (error) { 11 | rsErrorCalled = true; 12 | assert_equals(error.url, "file:///nonexistent"); 13 | assert_equals(error.errorCode, 203); 14 | assert_regexp_match(error.errorString, 15 | /^Error opening\b.*?\bnonexistent:/); 16 | }); 17 | 18 | page.open(url, this.step_func_done(function () { 19 | assert_is_true(rsErrorCalled); 20 | })); 21 | 22 | }, "attempts to load a file: URL in an iframe with --local-url-access=yes"); 23 | -------------------------------------------------------------------------------- /test/module/webpage/local-urls-enabled.js: -------------------------------------------------------------------------------- 1 | //! phantomjs: --local-url-access=yes 2 | 3 | var webpage = require("webpage"); 4 | 5 | async_test(function () { 6 | var page = webpage.create(); 7 | var url = "file:///nonexistent"; 8 | var rsErrorCalled = false; 9 | 10 | page.onResourceError = this.step_func(function (error) { 11 | rsErrorCalled = true; 12 | assert_equals(error.url, url); 13 | assert_equals(error.errorCode, 203); 14 | assert_regexp_match(error.errorString, 15 | /^Error opening\b.*?\bnonexistent:/); 16 | }); 17 | 18 | page.open(url, this.step_func_done(function () { 19 | assert_is_true(rsErrorCalled); 20 | })); 21 | 22 | }, "attempts to load a file: URL with --local-url-access=yes"); 23 | -------------------------------------------------------------------------------- /test/module/webpage/long-running-javascript.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | var page = require('webpage').create(); 3 | 4 | page.onLongRunningScript = this.step_func_done(function () { 5 | page.stopJavaScript(); 6 | }); 7 | 8 | page.open(TEST_HTTP_BASE + "js-infinite-loop.html", 9 | this.step_func(function (s) { 10 | assert_equals(s, "success"); 11 | })); 12 | 13 | }, "page.onLongRunningScript can interrupt scripts", { 14 | skip: true // https://github.com/ariya/phantomjs/issues/13490 15 | // The underlying WebKit feature is so broken that an 16 | // infinite loop in a _page_ script prevents timeouts 17 | // from firing in the _controller_! 18 | }); 19 | -------------------------------------------------------------------------------- /test/module/webpage/modify-header.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | var webpage = require('webpage'); 3 | 4 | // NOTE: HTTP header names are case-insensitive. Our test server 5 | // returns the name in lowercase. 6 | 7 | var page = webpage.create(); 8 | assert_type_of(page.customHeaders, 'object'); 9 | assert_deep_equals(page.customHeaders, {}); 10 | 11 | page.customHeaders = { 'CustomHeader': 'CustomValue' }; 12 | 13 | page.onResourceRequested = this.step_func(function(requestData, request) { 14 | assert_type_of(request.setHeader, 'function'); 15 | request.setHeader('CustomHeader', 'ModifiedCustomValue'); 16 | }); 17 | 18 | page.open(TEST_HTTP_BASE + 'echo', this.step_func_done(function (status) { 19 | var json, headers; 20 | assert_equals(status, 'success'); 21 | json = JSON.parse(page.plainText); 22 | headers = json.headers; 23 | assert_own_property(headers, 'customheader'); 24 | assert_equals(headers.customheader, 'ModifiedCustomValue'); 25 | })); 26 | 27 | }, "modifying HTTP headers"); 28 | -------------------------------------------------------------------------------- /test/module/webpage/mouseclick-event.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var page = require('webpage').create(); 3 | 4 | page.evaluate(function() { 5 | window.addEventListener('mousedown', function(event) { 6 | window.loggedEvent = window.loggedEvent || {}; 7 | window.loggedEvent.mousedown = event; 8 | }, false); 9 | window.addEventListener('mouseup', function(event) { 10 | window.loggedEvent = window.loggedEvent || {}; 11 | window.loggedEvent.mouseup = event; 12 | }, false); 13 | }); 14 | page.sendEvent('click', 42, 217); 15 | 16 | var event = page.evaluate(function() { 17 | return window.loggedEvent; 18 | }); 19 | assert_equals(event.mouseup.clientX, 42); 20 | assert_equals(event.mouseup.clientY, 217); 21 | assert_equals(event.mousedown.clientX, 42); 22 | assert_equals(event.mousedown.clientY, 217); 23 | 24 | // click with modifier key 25 | page.evaluate(function() { 26 | window.addEventListener('click', function(event) { 27 | window.loggedEvent = window.loggedEvent || {}; 28 | window.loggedEvent.click = event; 29 | }, false); 30 | }); 31 | page.sendEvent('click', 100, 100, 'left', page.event.modifier.shift); 32 | 33 | var event = page.evaluate(function() { 34 | return window.loggedEvent.click; 35 | }); 36 | assert_is_true(event.shiftKey); 37 | 38 | }, "mouse click events"); 39 | -------------------------------------------------------------------------------- /test/module/webpage/mousedoubleclick-event.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var page = require('webpage').create(); 3 | 4 | page.content = ''; 5 | var point = page.evaluate(function () { 6 | var el = document.querySelector('input'); 7 | var rect = el.getBoundingClientRect(); 8 | return { x: rect.left + Math.floor(rect.width / 2), y: rect.top + (rect.height / 2) }; 9 | }); 10 | page.sendEvent('doubleclick', point.x, point.y); 11 | 12 | var text = page.evaluate(function () { 13 | return document.querySelector('input').value; 14 | }); 15 | assert_equals(text, "doubleclicked"); 16 | 17 | // click with modifier key 18 | page.evaluate(function() { 19 | window.addEventListener('dblclick', function(event) { 20 | window.loggedEvent = window.loggedEvent || {}; 21 | window.loggedEvent.dblclick = event; 22 | }, false); 23 | }); 24 | page.sendEvent('doubleclick', 100, 100, 'left', page.event.modifier.shift); 25 | 26 | var event = page.evaluate(function() { 27 | return window.loggedEvent.dblclick; 28 | }); 29 | assert_is_true(event.shiftKey); 30 | }, "mouse double-click events"); 31 | -------------------------------------------------------------------------------- /test/module/webpage/mousedown-event.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var page = require('webpage').create(); 3 | 4 | page.evaluate(function() { 5 | window.addEventListener('mousedown', function(event) { 6 | window.loggedEvent = window.loggedEvent || []; 7 | window.loggedEvent.push(event); 8 | }, false); 9 | }); 10 | 11 | page.sendEvent('mousedown', 42, 217); 12 | var loggedEvent = page.evaluate(function() { 13 | return window.loggedEvent; 14 | }); 15 | assert_equals(loggedEvent.length, 1); 16 | assert_equals(loggedEvent[0].clientX, 42); 17 | assert_equals(loggedEvent[0].clientY, 217); 18 | 19 | page.sendEvent('mousedown', 100, 100, 'left', page.event.modifier.shift); 20 | loggedEvent = page.evaluate(function() { 21 | return window.loggedEvent; 22 | }); 23 | assert_equals(loggedEvent.length, 2); 24 | assert_is_true(loggedEvent[1].shiftKey); 25 | 26 | }, "mouse-down events"); 27 | -------------------------------------------------------------------------------- /test/module/webpage/mousemove-event.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var page = require('webpage').create(); 3 | 4 | page.evaluate(function() { 5 | window.addEventListener('mousemove', function(event) { 6 | window.loggedEvent = window.loggedEvent || []; 7 | window.loggedEvent.push(event); 8 | }, false); 9 | }); 10 | 11 | page.sendEvent('mousemove', 14, 3); 12 | var loggedEvent = page.evaluate(function() { 13 | return window.loggedEvent; 14 | }); 15 | assert_equals(loggedEvent.length, 1); 16 | assert_equals(loggedEvent[0].clientX, 14); 17 | assert_equals(loggedEvent[0].clientY, 3); 18 | }, "mouse-move events"); 19 | -------------------------------------------------------------------------------- /test/module/webpage/mouseup-event.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var webpage = require('webpage'); 3 | var page = webpage.create(); 4 | 5 | page.evaluate(function() { 6 | window.addEventListener('mouseup', function(event) { 7 | window.loggedEvent = window.loggedEvent || []; 8 | window.loggedEvent.push(event); 9 | }, false); 10 | }); 11 | 12 | page.sendEvent('mouseup', 42, 217); 13 | var loggedEvent = page.evaluate(function() { 14 | return window.loggedEvent; 15 | }); 16 | assert_equals(loggedEvent.length, 1); 17 | assert_equals(loggedEvent[0].clientX, 42); 18 | assert_equals(loggedEvent[0].clientY, 217); 19 | 20 | page.sendEvent('mouseup', 100, 100, 'left', page.event.modifier.shift); 21 | loggedEvent = page.evaluate(function() { 22 | return window.loggedEvent; 23 | }); 24 | assert_equals(loggedEvent.length, 2); 25 | assert_is_true(loggedEvent[1].shiftKey); 26 | }, "mouse-up events"); 27 | -------------------------------------------------------------------------------- /test/module/webpage/navigation.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | var page = require("webpage").create(); 3 | var url1 = TEST_HTTP_BASE + "navigation/index.html"; 4 | var url2 = TEST_HTTP_BASE + "navigation/dest.html"; 5 | 6 | var onLoadFinished1 = this.step_func(function (status) { 7 | assert_equals(status, "success"); 8 | assert_equals(page.url, url1); 9 | assert_equals(page.evaluate(function () { 10 | return document.body.innerHTML; 11 | }), "INDEX\n"); 12 | 13 | page.onLoadFinished = onLoadFinished2; 14 | page.evaluate(function() { 15 | window.location = "dest.html"; 16 | }); 17 | }); 18 | 19 | var onLoadFinished2 = this.step_func_done(function (status) { 20 | assert_equals(status, "success"); 21 | assert_equals(page.url, url2); 22 | assert_equals(page.evaluate(function () { 23 | return document.body.innerHTML; 24 | }), "DEST\n"); 25 | }); 26 | 27 | page.onLoadFinished = onLoadFinished1; 28 | page.open(url1); 29 | 30 | }, "navigating to a relative URL using window.location", 31 | { skip: true } // FIXME 32 | ); 33 | -------------------------------------------------------------------------------- /test/module/webpage/no-plugin.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | var webpage = require('webpage'); 3 | var page = webpage.create(); 4 | 5 | var pluginLength = page.evaluate(function() { 6 | return window.navigator.plugins.length; 7 | }); 8 | assert_equals(pluginLength, 0); 9 | 10 | page.open(TEST_HTTP_BASE + 'hello.html', 11 | this.step_func_done(function (status) { 12 | assert_equals(status, 'success'); 13 | var pluginLength = page.evaluate(function() { 14 | return window.navigator.plugins.length; 15 | }); 16 | assert_equals(pluginLength, 0); 17 | })); 18 | 19 | }, "window.navigator.plugins is empty"); 20 | -------------------------------------------------------------------------------- /test/module/webpage/on-confirm.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var page = require('webpage').create(); 3 | 4 | var msg = "message body", 5 | result, 6 | expected = true; 7 | 8 | assert_equals(page.onConfirm, undefined); 9 | 10 | var onConfirmTrue = function(msg) { 11 | return true; 12 | }; 13 | page.onConfirm = onConfirmTrue; 14 | assert_equals(page.onConfirm, onConfirmTrue); 15 | 16 | result = page.evaluate(function(m) { 17 | return window.confirm(m); 18 | }, msg); 19 | 20 | assert_equals(result, expected); 21 | 22 | var onConfirmFunc = function() { return !!"y"; }; 23 | page.onConfirm = onConfirmFunc; 24 | assert_equals(page.onConfirm, onConfirmFunc); 25 | assert_not_equals(page.onConfirm, onConfirmTrue); 26 | 27 | page.onConfirm = null; 28 | // Will only allow setting to a function value, so setting it to `null` returns `undefined` 29 | assert_equals(page.onConfirm, undefined); 30 | page.onConfirm = undefined; 31 | assert_equals(page.onConfirm, undefined); 32 | 33 | }, "page.onConfirm"); 34 | -------------------------------------------------------------------------------- /test/module/webpage/on-initialized.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var page = require('webpage').create(); 3 | 4 | assert_equals(page.onInitialized, undefined); 5 | 6 | var onInitialized1 = function() { var x = "x"; }; 7 | page.onInitialized = onInitialized1; 8 | assert_equals(page.onInitialized, onInitialized1); 9 | 10 | var onInitialized2 = function() { var y = "y"; }; 11 | page.onInitialized = onInitialized2; 12 | assert_equals(page.onInitialized, onInitialized2); 13 | assert_not_equals(page.onInitialized, onInitialized1); 14 | 15 | page.onInitialized = null; 16 | // Will only allow setting to a function value, so setting it to `null` returns `undefined` 17 | assert_equals(page.onInitialized, undefined); 18 | 19 | page.onInitialized = undefined; 20 | assert_equals(page.onInitialized, undefined); 21 | }, "page.onInitialized"); 22 | -------------------------------------------------------------------------------- /test/module/webpage/open.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | var webpage = require('webpage'); 3 | var page = webpage.create(); 4 | assert_type_of(page, 'object'); 5 | 6 | page.onResourceReceived = this.step_func(function (resource) { 7 | assert_equals(resource.status, 200); 8 | }); 9 | page.open(TEST_HTTP_BASE + 'hello.html', 10 | this.step_func_done(function (status) { 11 | assert_equals(status, 'success'); 12 | assert_type_of(page.title, 'string'); 13 | assert_equals(page.title, 'Hello'); 14 | assert_type_of(page.plainText, 'string'); 15 | assert_equals(page.plainText, 'Hello, world!'); 16 | })); 17 | }, "opening a webpage"); 18 | 19 | async_test(function () { 20 | var webpage = require('webpage'); 21 | var page = webpage.create(); 22 | 23 | // both onResourceReceived and onResourceError should be called 24 | page.onResourceReceived = this.step_func(function (resource) { 25 | assert_equals(resource.status, 401); 26 | }); 27 | page.onResourceError = this.step_func(function (err) { 28 | assert_equals(err.errorString, "Operation canceled"); 29 | }); 30 | 31 | page.open(TEST_HTTP_BASE + 'status?status=401' + 32 | '&WWW-Authenticate=Basic%20realm%3D%22PhantomJS%20test%22', 33 | this.step_func_done(function (status) { 34 | assert_equals(status, 'fail'); 35 | })); 36 | 37 | }, "proper handling of HTTP error responses"); 38 | 39 | async_test(function () { 40 | var webpage = require('webpage'); 41 | var page = webpage.create(); 42 | 43 | page.settings.resourceTimeout = 1; 44 | 45 | // This is all you have to do to assert that a hook does get called. 46 | page.onResourceTimeout = this.step_func(function(){}); 47 | 48 | page.open(TEST_HTTP_BASE + "delay?5", 49 | this.step_func_done(function (s) { 50 | assert_not_equals(s, "success"); 51 | })); 52 | 53 | }, "onResourceTimeout fires after resourceTimeout ms"); 54 | -------------------------------------------------------------------------------- /test/module/webpage/postdata.js: -------------------------------------------------------------------------------- 1 | function validate_echo_response (status, page, postdata) { 2 | assert_equals(status, 'success'); 3 | 4 | var desc = JSON.parse(page.plainText); 5 | assert_equals(desc.command, "POST"); 6 | assert_equals(desc.postdata, postdata); 7 | assert_equals(desc.headers['content-type'], 8 | 'application/x-www-form-urlencoded'); 9 | } 10 | 11 | async_test(function () { 12 | 13 | var utfString = '안녕'; 14 | var openOptions = { 15 | operation: 'POST', 16 | data: utfString, 17 | encoding: 'utf8' 18 | }; 19 | var pageOptions = { 20 | onLoadFinished: this.step_func_done(function(status) { 21 | validate_echo_response(status, page, utfString); 22 | }) 23 | }; 24 | var page = new WebPage(pageOptions); 25 | page.openUrl(TEST_HTTP_BASE + "echo", openOptions, {}); 26 | 27 | 28 | }, "processing request body for POST"); 29 | 30 | async_test(function () { 31 | 32 | var postdata = "ab=cd"; 33 | var pageOptions = { 34 | onResourceRequested: this.step_func(function (request) { 35 | assert_equals(request.postData, postdata); 36 | }), 37 | onLoadFinished: this.step_func_done(function (status) { 38 | validate_echo_response(status, page, postdata); 39 | }) 40 | }; 41 | 42 | var page = new WebPage(pageOptions); 43 | page.open(TEST_HTTP_BASE + "echo", 'post', postdata); 44 | 45 | 46 | }, "POST data is available in onResourceRequested"); 47 | -------------------------------------------------------------------------------- /test/module/webpage/prompt.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var page = require('webpage').create(); 3 | 4 | var msg = "message", 5 | value = "value", 6 | result, 7 | expected = "extra-value"; 8 | page.onPrompt = function(msg, value) { 9 | return "extra-"+value; 10 | }; 11 | result = page.evaluate(function(m, v) { 12 | return window.prompt(m, v); 13 | }, msg, value); 14 | 15 | assert_equals(result, expected); 16 | }, "page.onPrompt"); 17 | -------------------------------------------------------------------------------- /test/module/webpage/remove-header.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | // NOTE: HTTP header names are case-insensitive. Our test server 4 | // returns the name in lowercase. 5 | async_test(function () { 6 | var page = webpage.create(); 7 | assert_type_of(page.customHeaders, 'object'); 8 | assert_deep_equals(page.customHeaders, {}); 9 | 10 | page.customHeaders = { 'CustomHeader': 'ModifiedCustomValue' }; 11 | 12 | page.onResourceRequested = this.step_func(function(requestData, request) { 13 | assert_type_of(request.setHeader, 'function'); 14 | request.setHeader('CustomHeader', null); 15 | }); 16 | 17 | page.open(TEST_HTTP_BASE + 'echo', 18 | this.step_func_done(function (status) { 19 | var json, headers; 20 | assert_equals(status, 'success'); 21 | json = JSON.parse(page.plainText); 22 | headers = json.headers; 23 | assert_no_property(headers, 'customheader'); 24 | assert_no_property(headers, 'CustomHeader'); 25 | })); 26 | }); 27 | -------------------------------------------------------------------------------- /test/module/webpage/render.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var system = require("system"); 3 | var webpage = require("webpage"); 4 | var renders = require("./renders"); 5 | 6 | function clean_pdf(data) { 7 | // FIXME: This is not nearly enough normalization. 8 | data = data.replace(/\/(Title|Creator|Producer|CreationDate) \([^\n]*\)/g, "/$1 ()"); 9 | data = data.replace(/\nxref\n[0-9 nf\n]+trailer\b/, "\ntrailer"); 10 | data = data.replace(/\nstartxref\n[0-9]+\n%%EOF\n/, "\n"); 11 | return data; 12 | } 13 | 14 | function render_test(format, option) { 15 | var opt = option || {}; 16 | var scratch = "temp_render"; 17 | if (!opt.format) { 18 | scratch += "."; 19 | scratch += format; 20 | } 21 | var expect_content = renders.get(format, opt.quality || ""); 22 | var p = webpage.create(); 23 | 24 | p.paperSize = { width: '300px', height: '300px', border: '0px' }; 25 | p.clipRect = { top: 0, left: 0, width: 300, height: 300}; 26 | p.viewportSize = { width: 300, height: 300}; 27 | 28 | p.open(TEST_HTTP_BASE + "render/", this.step_func_done(function (status) { 29 | p.render(scratch, opt); 30 | this.add_cleanup(function () { fs.remove(scratch); }); 31 | var content = fs.read(scratch, "b"); 32 | 33 | // expected variation in PDF output 34 | if (format === "pdf") { 35 | content = clean_pdf(content); 36 | expect_content = clean_pdf(expect_content); 37 | } 38 | 39 | // Don't dump entire images to the log on failure. 40 | assert_is_true(content === expect_content); 41 | })); 42 | } 43 | 44 | [ 45 | ["PDF", "pdf", {}], 46 | ["PDF (format option)", "pdf", {format: "pdf"}], 47 | ["PNG", "png", {}], 48 | ["PNG (format option)", "png", {format: "png"}], 49 | ["JPEG", "jpg", {}], 50 | ["JPEG (format option)", "jpg", {format: "jpg"}], 51 | ["JPEG (quality option)", "jpg", {quality: 50}], 52 | ["JPEG (format and quality options)", "jpg", {format: "jpg", quality: 50}], 53 | ] 54 | .forEach(function (arr) { 55 | var label = arr[0]; 56 | var format = arr[1]; 57 | var opt = arr[2]; 58 | var props = {}; 59 | 60 | // All tests except JPG fail. 61 | if (format !== "jpg") 62 | props.expected_fail = true; 63 | 64 | props.skip = true; // FIXME 65 | 66 | async_test(function () { render_test.call(this, format, opt); }, 67 | label, props); 68 | }); 69 | -------------------------------------------------------------------------------- /test/module/webpage/renderBase64.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var system = require("system"); 3 | var webpage = require("webpage"); 4 | var renders = require("./renders"); 5 | 6 | function clean_pdf(data) { 7 | // FIXME: This is not nearly enough normalization. 8 | data = data.replace(/\/(Title|Creator|Producer|CreationDate) \([^\n]*\)/g, "/$1 ()"); 9 | data = data.replace(/\nxref\n[0-9 nf\n]+trailer\b/, "\ntrailer"); 10 | data = data.replace(/\nstartxref\n[0-9]+\n%%EOF\n/, "\n"); 11 | return data; 12 | } 13 | 14 | function render_test(format) { 15 | var expect_content = btoa(renders.get(format, "")); 16 | var p = webpage.create(); 17 | 18 | p.paperSize = { width: '300px', height: '300px', border: '0px' }; 19 | p.clipRect = { top: 0, left: 0, width: 300, height: 300}; 20 | p.viewportSize = { width: 300, height: 300}; 21 | 22 | p.open(TEST_HTTP_BASE + "render/", this.step_func_done(function (status) { 23 | var content = p.renderBase64(format); 24 | 25 | // expected variation in PDF output 26 | if (format === "pdf") { 27 | content = clean_pdf(content); 28 | expect_content = clean_pdf(expect_content); 29 | } 30 | 31 | // Don't dump entire images to the log on failure. 32 | assert_is_true(content === expect_content); 33 | })); 34 | } 35 | 36 | [ 37 | "pdf", 38 | "png", 39 | "jpg", 40 | ] 41 | .forEach(function (format) { 42 | var props = {}; 43 | 44 | // All tests except JPG fail. 45 | if (format !== "jpg") 46 | props.expected_fail = true; 47 | 48 | props.skip = true; // FIXME 49 | 50 | async_test(function () { render_test.call(this, format); }, 51 | format, props); 52 | }); 53 | -------------------------------------------------------------------------------- /test/module/webpage/renders/index.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | 3 | exports.get = function get(format, quality) { 4 | var expect_file = fs.join( 5 | module.dirname, "test" + quality + "." + format); 6 | return fs.read(expect_file, "b"); 7 | }; 8 | -------------------------------------------------------------------------------- /test/module/webpage/renders/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/test/module/webpage/renders/test.jpg -------------------------------------------------------------------------------- /test/module/webpage/renders/test.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/test/module/webpage/renders/test.pdf -------------------------------------------------------------------------------- /test/module/webpage/renders/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/test/module/webpage/renders/test.png -------------------------------------------------------------------------------- /test/module/webpage/renders/test50.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariya/phantomjs/0a0b0facb16acfbabb7804822ecaf4f4b9dce3d2/test/module/webpage/renders/test50.jpg -------------------------------------------------------------------------------- /test/module/webpage/repaint-requested.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | async_test(function () { 4 | var page = webpage.create(); 5 | var requestCount = 0; 6 | 7 | page.onRepaintRequested = this.step_func(function(x, y, w, h) { 8 | if ((w > 0) && (h > 0)) { 9 | ++requestCount; 10 | } 11 | }); 12 | 13 | page.open(TEST_HTTP_BASE + 'hello.html', 14 | this.step_func_done(function (status) { 15 | assert_equals(status, 'success'); 16 | assert_greater_than(requestCount, 0); 17 | })); 18 | 19 | }, "onRepaintRequested should be called at least once for each page load"); 20 | -------------------------------------------------------------------------------- /test/module/webpage/resource-received-error.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | async_test(function () { 4 | var page = webpage.create(); 5 | var url = TEST_HTTP_BASE + 'status?400'; 6 | var startStage = 0; 7 | var endStage = 0; 8 | var errors = 0; 9 | 10 | page.onResourceReceived = this.step_func(function (resource) { 11 | assert_equals(resource.url, url); 12 | if (resource.stage === 'start') { 13 | ++startStage; 14 | } 15 | if (resource.stage === 'end') { 16 | ++endStage; 17 | } 18 | }); 19 | page.onResourceError = this.step_func(function (error) { 20 | assert_equals(error.url, url); 21 | assert_equals(error.status, 400); 22 | ++errors; 23 | }); 24 | 25 | page.open(url, this.step_func_done(function (status) { 26 | assert_equals(status, 'success'); 27 | assert_equals(startStage, 1); 28 | assert_equals(endStage, 1); 29 | assert_equals(errors, 1); 30 | })); 31 | 32 | }, "onResourceReceived should still be called for failed requests"); 33 | -------------------------------------------------------------------------------- /test/module/webpage/resource-request-error.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | async_test(function () { 4 | var page = webpage.create(); 5 | var resourceErrors = 0; 6 | 7 | page.onResourceError = this.step_func(function(err) { 8 | ++resourceErrors; 9 | 10 | assert_equals(err.status, 404); 11 | assert_equals(err.statusText, 'File not found'); 12 | assert_equals(err.url, TEST_HTTP_BASE + 'notExist.png'); 13 | assert_equals(err.errorCode, 203); 14 | assert_regexp_match(err.errorString, 15 | /Error downloading http:\/\/localhost:[0-9]+\/notExist\.png/); 16 | assert_regexp_match(err.errorString, 17 | /server replied: File not found/); 18 | }); 19 | 20 | page.open(TEST_HTTP_BASE + 'missing-img.html', 21 | this.step_func_done(function (status) { 22 | assert_equals(status, 'success'); 23 | assert_equals(resourceErrors, 1); 24 | })); 25 | 26 | }, "resourceError basic functionality", 27 | { skip: true } // FIXME 28 | ); 29 | 30 | -------------------------------------------------------------------------------- /test/module/webpage/scroll-position.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | test(function () { 4 | var defaultPage = webpage.create(); 5 | assert_deep_equals(defaultPage.scrollPosition, {left:0,top:0}); 6 | }, "default scroll position"); 7 | 8 | test(function () { 9 | var options = { 10 | scrollPosition: { 11 | left: 1, 12 | top: 2 13 | } 14 | }; 15 | var customPage = webpage.create(options); 16 | assert_deep_equals(customPage.scrollPosition, options.scrollPosition); 17 | }, "custom scroll position"); 18 | -------------------------------------------------------------------------------- /test/module/webpage/set-content.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | test(function () { 4 | var page = webpage.create(); 5 | var expectedContent = '
Test div
'; 6 | var expectedLocation = 'http://www.phantomjs.org/'; 7 | page.setContent(expectedContent, expectedLocation); 8 | 9 | var actualContent = page.evaluate(function() { 10 | return document.documentElement.textContent; 11 | }); 12 | assert_equals(actualContent, 'Test div'); 13 | 14 | var actualLocation = page.evaluate(function() { 15 | return window.location.href; 16 | }); 17 | assert_equals(actualLocation, expectedLocation); 18 | 19 | }, "manually set page content and location"); 20 | -------------------------------------------------------------------------------- /test/module/webpage/set-frame-content.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | test(function () { 4 | var page = webpage.create(); 5 | page.setContent('', 'http://example.com'); 6 | 7 | page.switchToFrame(page.framesName[0]); 8 | var expectedContent = '
Test div
'; 9 | var expectedLocation = 'http://www.phantomjs.org/'; 10 | page.setFrameContent(expectedContent, expectedLocation); 11 | 12 | // Go back to the main page and make sure it isn't changed. 13 | page.switchToParentFrame(); 14 | var actualContent = page.evaluate(function() { 15 | return document.documentElement.textContent; 16 | }); 17 | assert_not_equals(actualContent, 'Test div'); 18 | 19 | var actualLocation = page.evaluate(function() { 20 | return window.location.href; 21 | }); 22 | assert_not_equals(actualLocation, expectedLocation); 23 | 24 | // Go to the iframe and make sure it changed. 25 | page.switchToFrame(page.framesName[0]); 26 | var actualContent = page.evaluate(function() { 27 | return document.documentElement.textContent; 28 | }); 29 | assert_equals(actualContent, 'Test div'); 30 | 31 | var actualLocation = page.evaluate(function() { 32 | return window.location.href; 33 | }); 34 | assert_equals(actualLocation, expectedLocation); 35 | 36 | }, "manually set iframe page content and location"); 37 | -------------------------------------------------------------------------------- /test/module/webpage/user-agent.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | async_test(function () { 4 | var ua = 'PHANTOMJS-TEST-USER-AGENT'; 5 | var page = webpage.create({ 6 | settings: { 7 | userAgent: ua 8 | } 9 | }); 10 | 11 | assert_equals(page.settings.userAgent, ua); 12 | 13 | page.open(TEST_HTTP_BASE + 'user-agent.html', 14 | this.step_func_done(function (status) { 15 | assert_equals(status, 'success'); 16 | var agent = page.evaluate(function() { 17 | return document.getElementById('ua').textContent; 18 | }); 19 | assert_equals(agent, ua); 20 | })); 21 | 22 | }, "load a page with a custom user agent"); 23 | -------------------------------------------------------------------------------- /test/module/webpage/viewport-size.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | test(function () { 4 | var defaultPage = webpage.create(); 5 | assert_deep_equals(defaultPage.viewportSize, {height:300,width:400}); 6 | }, "default viewport size"); 7 | 8 | test(function () { 9 | var options = { 10 | viewportSize: { 11 | height: 100, 12 | width: 200 13 | } 14 | }; 15 | var customPage = webpage.create(options); 16 | assert_deep_equals(customPage.viewportSize, options.viewportSize); 17 | }, "custom viewport size"); 18 | -------------------------------------------------------------------------------- /test/module/webpage/window.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | assert_own_property(window, 'WebPage'); 3 | assert_type_of(window.WebPage, 'function'); 4 | }, "window.WebPage global property"); 5 | -------------------------------------------------------------------------------- /test/module/webpage/zoom-factor.js: -------------------------------------------------------------------------------- 1 | var webpage = require('webpage'); 2 | 3 | test(function () { 4 | var page = webpage.create(); 5 | assert_equals(page.zoomFactor, 1.0); 6 | 7 | page.zoomFactor = 1.5; 8 | assert_equals(page.zoomFactor, 1.5); 9 | 10 | page.zoomFactor = 2.0; 11 | assert_equals(page.zoomFactor, 2.0); 12 | 13 | page.zoomFactor = 0.5; 14 | assert_equals(page.zoomFactor, 0.5); 15 | }, "page.zoomFactor"); 16 | 17 | // TODO: render using zoomFactor != 1 and check the result 18 | -------------------------------------------------------------------------------- /test/module/webserver/basics.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | assert_no_property(window, "WebServer", 3 | "WebServer constructor should not be global"); 4 | 5 | var WebServer = require("webserver").create; 6 | assert_type_of(WebServer, "function"); 7 | 8 | }, "WebServer constructor"); 9 | 10 | test(function () { 11 | var server = require("webserver").create(); 12 | 13 | assert_not_equals(server, null); 14 | assert_type_of(server, "object"); 15 | assert_equals(server.objectName, "WebServer"); 16 | 17 | assert_own_property(server, "port"); 18 | assert_type_of(server.port, "string"); 19 | assert_equals(server.port, ""); 20 | 21 | assert_type_of(server.listenOnPort, "function"); 22 | assert_type_of(server.newRequest, "function"); 23 | assert_type_of(server.close, "function"); 24 | 25 | }, "WebServer object properties"); 26 | -------------------------------------------------------------------------------- /test/regression/README: -------------------------------------------------------------------------------- 1 | Tests in this directory are named for their bug number. 2 | pjs-NNNN corresponds to https://github.com/ariya/phantomjs/issues/NNNN. 3 | webkit-NNNN corresponds to ​https://bugs.webkit.org/show_bug.cgi?id=NNNN. 4 | -------------------------------------------------------------------------------- /test/regression/pjs-10690.js: -------------------------------------------------------------------------------- 1 | // Issue 10690: the second page load used to crash on OSX. 2 | 3 | var url = TEST_HTTP_BASE + 'regression/pjs-10690/index.html'; 4 | function do_test() { 5 | var page = require('webpage').create(); 6 | 7 | page.open(url, this.step_func_done (function (status) { 8 | assert_equals(status, "success"); 9 | page.release(); 10 | })); 11 | } 12 | 13 | async_test(do_test, "load a page with a downloadable font, once"); 14 | async_test(do_test, "load a page with a downloadable font, again"); 15 | -------------------------------------------------------------------------------- /test/regression/pjs-12482.js: -------------------------------------------------------------------------------- 1 | //! no-harness 2 | 3 | // https://github.com/ariya/phantomjs/issues/12482 4 | // regression caused by fix for 5 | // https://github.com/ariya/phantomjs/issues/12431 6 | 7 | var webpage = require('webpage'); 8 | var sys = require('system'); 9 | 10 | var pages = [ 11 | webpage.create(), 12 | webpage.create(), 13 | webpage.create() 14 | ]; 15 | 16 | var loaded = 0; 17 | 18 | sys.stdout.write("1.." + pages.length + "\n"); 19 | setTimeout(function () { phantom.exit(1); }, 200); 20 | 21 | function loadHook (status) { 22 | loaded++; 23 | if (status === "success") { 24 | sys.stdout.write("ok " + loaded + " loading page\n"); 25 | } else { 26 | sys.stdout.write("not ok " + loaded + " loading page\n"); 27 | } 28 | 29 | if (loaded === pages.length) { 30 | pages[1].close(); 31 | setTimeout(function(){ 32 | phantom.exit(0); 33 | sys.stdout.write("not ok " + (pages.length+1) + 34 | " should not get here # TODO\n"); 35 | }, 50); 36 | } 37 | } 38 | function consoleHook (msg) { 39 | sys.stdout.write(msg + "\n"); 40 | } 41 | 42 | for (var i = 0; i < pages.length; i++) { 43 | pages[i].onConsoleMessage = consoleHook; 44 | pages[i].open( 45 | "data:text/html,", 47 | loadHook); 48 | } 49 | -------------------------------------------------------------------------------- /test/regression/pjs-13551.js: -------------------------------------------------------------------------------- 1 | // Issue #13551: Crash when switching "back" from frame that no longer 2 | // exists (for whatever reason) 3 | 4 | var webpage = require('webpage'); 5 | 6 | function test_template(parent, action) { 7 | var page; 8 | var url = TEST_HTTP_BASE + 9 | "regression/pjs-13551/" + parent + "-parent.html"; 10 | var s_callback0, s_callback1, s_callback2; 11 | 12 | function callback0 (n) { 13 | assert_equals(n, 0); 14 | page.onCallback = s_callback1; 15 | page.evaluate(function () { 16 | document.getElementById("prepare").click(); 17 | }); 18 | } 19 | function callback1 (n) { 20 | assert_equals(n, 1); 21 | page.onCallback = s_callback2; 22 | assert_equals(page.switchToFrame("target"), true); 23 | assert_equals(page.switchToFrame("actor"), true); 24 | page.evaluate(function () { 25 | document.getElementById("execute").click(); 26 | }); 27 | } 28 | function callback2 (n) { 29 | assert_equals(n, 2); 30 | assert_is_true(action == 'main' || action == 'parent'); 31 | if (action == 'main') { 32 | page.switchToMainFrame(); // Crash here 33 | } else { 34 | page.switchToParentFrame(); // Or here 35 | } 36 | } 37 | 38 | return function test_action () { 39 | page = webpage.create(); 40 | s_callback0 = this.step_func(callback0); 41 | s_callback1 = this.step_func(callback1); 42 | s_callback2 = this.step_func_done(callback2); 43 | page.onCallback = s_callback0; 44 | page.open(url); 45 | }; 46 | } 47 | 48 | async_test(test_template('closing', 'main'), "main from closed"); 49 | async_test(test_template('closing', 'parent'), "parent from closed"); 50 | async_test(test_template('reloading', 'main'), "main from reloaded"); 51 | async_test(test_template('reloading', 'parent'), "parent from reloaded"); 52 | -------------------------------------------------------------------------------- /test/regression/webkit-60448.js: -------------------------------------------------------------------------------- 1 | var url = TEST_HTTP_BASE + "regression/webkit-60448.html"; 2 | 3 | async_test(function () { 4 | var p = require("webpage").create(); 5 | p.open(url, this.step_func_done(function (status) { 6 | assert_equals(status, "success"); 7 | assert_is_true(p.evaluate(function () { 8 | return document.getElementById("test") === null; 9 | })); 10 | })); 11 | }, 12 | "remove an inline HTML element from the document"); 13 | -------------------------------------------------------------------------------- /test/standards/console/console_log.js: -------------------------------------------------------------------------------- 1 | async_test(function () { 2 | var page = require('webpage').create(); 3 | page.onConsoleMessage = this.step_func_done(function (msg) { 4 | assert_equals(msg, "answer 42"); 5 | }); 6 | page.evaluate(function () { 7 | console.log('answer', 42); 8 | }); 9 | }, "console.log should support multiple arguments", 10 | { skip: true } // FIXME 11 | ); 12 | 13 | -------------------------------------------------------------------------------- /test/standards/javascript/arrow.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var result = [2, 3, 5].map(x => x * x); 3 | assert_equals(result.length, 3); 4 | assert_equals(result.join(' '), '4 9 25'); 5 | }, "ES2015 arrow function"); 6 | -------------------------------------------------------------------------------- /test/standards/javascript/class.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | class Vehicle { }; 3 | assert_type_of(Vehicle, 'function'); 4 | }, "ES2015 class declaration"); 5 | 6 | test(function () { 7 | class Vehicle { constructor(n) { this.name = n } }; 8 | var v = new Vehicle('daily driver'); 9 | assert_type_of(Vehicle, 'function'); 10 | assert_type_of(Vehicle.constructor, 'function'); 11 | assert_type_of(v, 'object') 12 | }, "ES2015 class constructor"); 13 | 14 | 15 | test(function () { 16 | class Vehicle { 17 | constructor(n) { this._name = n } 18 | get name() { return this._name } 19 | } 20 | var v = new Vehicle('daily driver'); 21 | assert_type_of(v.name, 'string') 22 | assert_equals(v.name, 'daily driver'); 23 | }, "ES2015 class getter"); 24 | 25 | test(function () { 26 | class Vehicle { 27 | get name() { return this._name } 28 | set name(n) { this._name = n } 29 | } 30 | var v = new Vehicle(); 31 | v.name = 'daily driver'; 32 | assert_type_of(v.name, 'string') 33 | assert_equals(v.name, 'daily driver'); 34 | }, "ES2015 class setter"); 35 | -------------------------------------------------------------------------------- /test/standards/javascript/date.js: -------------------------------------------------------------------------------- 1 | test(function() { 2 | var date = new Date('2012-09-07'); 3 | assert_not_equals(date.toString(), 'Invalid Date'); 4 | assert_equals(date.getUTCDate(), 7); 5 | assert_equals(date.getUTCMonth(), 8); 6 | assert_equals(date.getYear(), 112); 7 | }, "new Date()"); 8 | 9 | test(function () { 10 | var date = Date.parse("2012-01-01"); 11 | assert_equals(date, 1325376000000); 12 | }, "Date.parse()"); 13 | -------------------------------------------------------------------------------- /test/standards/javascript/default.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | function inc(x, step = 1) { return x + step } 3 | assert_equals(inc(4), 5); 4 | assert_equals(inc(4, 3), 7); 5 | }, "ES2015 default parameter value"); 6 | -------------------------------------------------------------------------------- /test/standards/javascript/destructuring.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var o = { d: 14, m: 3 }; 3 | var { d: foo, m: bar } = o; 4 | assert_type_of(foo, 'number'); 5 | assert_type_of(bar, 'number'); 6 | assert_equals(foo, 14); 7 | assert_equals(bar, 3); 8 | }, "ES2015 object destructuring"); 9 | 10 | test(function () { 11 | var d, m; 12 | [d, m] = [14, 3]; 13 | assert_type_of(d, 'number'); 14 | assert_type_of(m, 'number'); 15 | assert_equals(d, 14); 16 | assert_equals(m, 3); 17 | }, "ES2015 array destructuring"); 18 | 19 | test(function () { 20 | var x = 14, y = 3; 21 | [x, y] = [y, x]; 22 | assert_equals(x, 3); 23 | assert_equals(y, 14); 24 | }, "ES2015 variable swap"); 25 | -------------------------------------------------------------------------------- /test/standards/javascript/function.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | assert_type_of(Function.length, 'number'); 3 | assert_type_of(Function.prototype, 'function'); 4 | assert_type_of(Function.prototype.apply, 'function'); 5 | assert_type_of(Function.prototype.bind, 'function'); 6 | assert_type_of(Function.prototype.call, 'function'); 7 | assert_type_of(Function.prototype.name, 'string'); 8 | assert_type_of(Function.prototype.toString, 'function'); 9 | }, "Function properties"); 10 | 11 | test(function () { 12 | var f = function foo(){}; 13 | assert_equals(f.name, 'foo'); 14 | }, ".name"); 15 | 16 | test(function () { 17 | assert_equals(Function.length, 1); 18 | assert_equals(function(){}.length, 0); 19 | assert_equals(function(x){}.length, 1); 20 | assert_equals(function(x, y){}.length, 2); 21 | assert_equals(function(x, y){}.length, 2); 22 | }, ".length"); 23 | 24 | test(function () { 25 | var args, keys, str, enumerable; 26 | (function() { 27 | args = arguments; 28 | keys = Object.keys(arguments); 29 | str = JSON.stringify(arguments); 30 | enumerable = false; 31 | for (var i in arguments) enumerable = true; 32 | })(14); 33 | 34 | assert_type_of(args, 'object'); 35 | assert_type_of(args.length, 'number'); 36 | assert_equals(args.toString(), '[object Arguments]'); 37 | assert_equals(args.length, 1); 38 | assert_equals(args[0], 14); 39 | 40 | assert_type_of(keys.length, 'number'); 41 | assert_equals(keys.length, 1); 42 | assert_equals(keys[0], "0"); 43 | 44 | assert_equals(str, '{"0":14}'); 45 | assert_is_true(enumerable); 46 | }, "arguments object"); 47 | -------------------------------------------------------------------------------- /test/standards/javascript/isarray.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | assert_type_of(Array.isArray, 'function'); 3 | assert_is_true(Array.isArray([])); 4 | assert_is_true(Array.isArray([1])); 5 | assert_is_true(Array.isArray([1, 2])); 6 | assert_is_false(Array.isArray({})); 7 | assert_is_false(Array.isArray(null)); 8 | }, "ES2015 Array.isArray"); 9 | -------------------------------------------------------------------------------- /test/standards/javascript/let.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | let x = 4; 3 | if (true) { 4 | let x = 7; 5 | assert_equals(x, 7); 6 | } 7 | assert_equals(x, 4); 8 | }, "ES2015 block-scope let"); 9 | -------------------------------------------------------------------------------- /test/standards/javascript/shorthand.js: -------------------------------------------------------------------------------- 1 | test(function () { 2 | var x = 14, y = 3; 3 | var obj = { x, y }; 4 | assert_type_of(obj.x, 'number'); 5 | assert_type_of(obj.y, 'number'); 6 | assert_equals(obj.x, 14); 7 | assert_equals(obj.y, 3); 8 | }, "ES2015 object literal property shorthand"); 9 | -------------------------------------------------------------------------------- /third-party.txt: -------------------------------------------------------------------------------- 1 | This document contains the list of Third Party Software included with 2 | PhantomJS, along with the license information. 3 | 4 | Third Party Software may impose additional restrictions and it is the 5 | user's responsibility to ensure that they have met the licensing 6 | requirements of PhantomJS and the relevant license of the Third Party 7 | Software they are using. 8 | 9 | Qt - http://qt-project.org/ 10 | License: GNU Lesser General Public License (LGPL) version 2.1. 11 | Reference: http://qt-project.org/doc/qt-4.8/lgpl.html. 12 | 13 | WebKit - http://www.webkit.org/ 14 | License: GNU Lesser General Public License (LGPL) version 2.1 and BSD. 15 | Reference: http://www.webkit.org/coding/lgpl-license.html and 16 | http://www.webkit.org/coding/bsd-license.html. 17 | 18 | Mongoose - https://github.com/cesanta/mongoose 19 | License: MIT 20 | Reference: https://github.com/cesanta/mongoose/commit/abbf27338ef554cce0281ac157aa71a9c1b82a55 21 | 22 | OpenSSL - http://www.openssl.org/ 23 | License: OpenSSL License, SSLeay License. 24 | Reference: http://www.openssl.org/source/license.html. 25 | 26 | Linenoise - https://github.com/tadmarshall/linenoise 27 | License: BSD. 28 | Reference: https://github.com/tadmarshall/linenoise/blob/master/linenoise.h. 29 | 30 | QCommandLine - http://xf.iksaif.net/dev/qcommandline.html 31 | License: GNU Lesser General Public License (LGPL) version 2.1. 32 | Reference: http://dev.iksaif.net/projects/qcommandline/repository/revisions/master/entry/COPYING 33 | 34 | wkhtmlpdf - http://wkhtmltopdf.org 35 | License: GNU Lesser General Public License (LGPL) 36 | Reference: https://github.com/wkhtmltopdf/wkhtmltopdf/blob/master/LICENSE 37 | -------------------------------------------------------------------------------- /tools/format-code.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cwd=$(pwd) 4 | clang-format-6.0 -i --style=WebKit $cwd/src/*.h $cwd/src/*.cpp 5 | -------------------------------------------------------------------------------- /tools/import-linenoise.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | LINENOISE_PATH="$PWD/../src/linenoise" 4 | LINENOISE_SRC_PATH="$LINENOISE_PATH/src" 5 | GITHUB_CLONE_URL="http://github.com/tadmarshall/linenoise.git" 6 | TO_REMOVE=".gitignore .git *.vcproj *.sln Makefile" 7 | 8 | 9 | # Make a new Linenoise source directory 10 | rm -rf $LINENOISE_SRC_PATH 11 | mkdir -p $LINENOISE_SRC_PATH 12 | 13 | # Cloning latest 'master' of Linenoise 14 | git clone $GITHUB_CLONE_URL $LINENOISE_SRC_PATH 15 | 16 | # From within the source directory... 17 | pushd $LINENOISE_SRC_PATH 18 | 19 | # Extract latest commit log info and prepare "README.md" content 20 | LATEST_COMMIT=$(git log -1) 21 | README_CONTENT=$(cat << EOF 22 | This project contains the **Linenoise project**, initially released 23 | by [Salvatore Sanfilippo](https://github.com/antirez). Here we import a fork 24 | by [Tad Marshall](https://github.com/tadmarshall) that lives at 25 | [github.com/tadmarshall/linenoise](https://github.com/tadmarshall/linenoise). 26 | 27 | The version of Linenoise included in PhantomJS refers to the commit: 28 | ----- 29 | $LATEST_COMMIT 30 | ----- 31 | 32 | Some files not needed for PhantomJS are removed. 33 | 34 | Linenoise is licensed under the BSD-license. 35 | Kudos to all the developers that contribute to this nice little pearl. 36 | 37 | EOF) 38 | 39 | # Remove unnecessary files 40 | rm -rf $TO_REMOVE 41 | 42 | popd # ... and out! 43 | 44 | # Save "README.md" 45 | echo "$README_CONTENT" > "$LINENOISE_PATH/README.md" 46 | --------------------------------------------------------------------------------